<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>项目实战-MIS系统 | 浪飞IT小栈</title>
    <meta name="generator" content="VuePress 1.9.9">
    <link rel="icon" href="/img/favicon.ico">
    <meta name="description" content="前后端技术分享">
    <meta name="keywords" content="前端博客,后端博客,人工智能,个人技术博客,前端,前端开发,前端框架,web前端,前端面试题,技术文档,学习,面试,JavaScript,js,ES6,TypeScript,vue,python,css3,html5,Node,git,github,markdown,java,Spring,Springboot,Redis,mysql">
    <meta name="baidu-site-verification" content="7F55weZDDc">
    <meta name="theme-color" content="#11a8cd">
    
    <link rel="preload" href="/assets/css/0.styles.ada71c49.css" as="style"><link rel="preload" href="/assets/js/app.a2a00aa5.js" as="script"><link rel="preload" href="/assets/js/2.256f807a.js" as="script"><link rel="preload" href="/assets/js/45.0ddf7e7f.js" as="script"><link rel="prefetch" href="/assets/js/10.ab144fe3.js"><link rel="prefetch" href="/assets/js/11.062e0879.js"><link rel="prefetch" href="/assets/js/12.f9c60882.js"><link rel="prefetch" href="/assets/js/13.0a6ebfcf.js"><link rel="prefetch" href="/assets/js/14.03fc6f12.js"><link rel="prefetch" href="/assets/js/15.19dbf9fd.js"><link rel="prefetch" href="/assets/js/16.6e68160b.js"><link rel="prefetch" href="/assets/js/17.1d678834.js"><link rel="prefetch" href="/assets/js/18.4536fd5c.js"><link rel="prefetch" href="/assets/js/19.9c1b65df.js"><link rel="prefetch" href="/assets/js/20.c5f96e71.js"><link rel="prefetch" href="/assets/js/21.3f0b334e.js"><link rel="prefetch" href="/assets/js/22.55c868be.js"><link rel="prefetch" href="/assets/js/23.91286241.js"><link rel="prefetch" href="/assets/js/24.c1af1909.js"><link rel="prefetch" href="/assets/js/25.a995a755.js"><link rel="prefetch" href="/assets/js/26.abc5dea3.js"><link rel="prefetch" href="/assets/js/27.1eb62850.js"><link rel="prefetch" href="/assets/js/28.b383a871.js"><link rel="prefetch" href="/assets/js/29.088e0d73.js"><link rel="prefetch" href="/assets/js/3.cd716564.js"><link rel="prefetch" href="/assets/js/30.3ccc98d5.js"><link rel="prefetch" href="/assets/js/31.aab7cc23.js"><link rel="prefetch" href="/assets/js/32.5e16b7e6.js"><link rel="prefetch" href="/assets/js/33.4aaeb741.js"><link rel="prefetch" href="/assets/js/34.45e8e898.js"><link rel="prefetch" href="/assets/js/35.5899c97a.js"><link rel="prefetch" href="/assets/js/36.32e2e263.js"><link rel="prefetch" href="/assets/js/37.c4e27bbd.js"><link rel="prefetch" href="/assets/js/38.fe5e60d2.js"><link rel="prefetch" href="/assets/js/39.2cb0b4ee.js"><link rel="prefetch" href="/assets/js/4.edf4d5e7.js"><link rel="prefetch" href="/assets/js/40.08d5bead.js"><link rel="prefetch" href="/assets/js/41.2f80f24b.js"><link rel="prefetch" href="/assets/js/42.43a49913.js"><link rel="prefetch" href="/assets/js/43.08da7ec2.js"><link rel="prefetch" href="/assets/js/44.7c7cb8a9.js"><link rel="prefetch" href="/assets/js/46.7c4609a5.js"><link rel="prefetch" href="/assets/js/47.edf3ddf8.js"><link rel="prefetch" href="/assets/js/48.569a90b9.js"><link rel="prefetch" href="/assets/js/49.fa368ac8.js"><link rel="prefetch" href="/assets/js/5.24054156.js"><link rel="prefetch" href="/assets/js/50.b9b3ea7f.js"><link rel="prefetch" href="/assets/js/51.a2ebf0fe.js"><link rel="prefetch" href="/assets/js/52.31f02238.js"><link rel="prefetch" href="/assets/js/53.4110ef1e.js"><link rel="prefetch" href="/assets/js/54.dab741c7.js"><link rel="prefetch" href="/assets/js/55.f27984e9.js"><link rel="prefetch" href="/assets/js/56.bd4c1a8e.js"><link rel="prefetch" href="/assets/js/57.375d40cb.js"><link rel="prefetch" href="/assets/js/58.932e3864.js"><link rel="prefetch" href="/assets/js/59.e657be1b.js"><link rel="prefetch" href="/assets/js/6.b259c061.js"><link rel="prefetch" href="/assets/js/60.88d94274.js"><link rel="prefetch" href="/assets/js/61.fa71d884.js"><link rel="prefetch" href="/assets/js/62.a9d3b3b7.js"><link rel="prefetch" href="/assets/js/63.f849fe75.js"><link rel="prefetch" href="/assets/js/64.1770f7a9.js"><link rel="prefetch" href="/assets/js/65.6afc33db.js"><link rel="prefetch" href="/assets/js/66.799f2eb4.js"><link rel="prefetch" href="/assets/js/67.f36b2f7d.js"><link rel="prefetch" href="/assets/js/68.868cd00b.js"><link rel="prefetch" href="/assets/js/69.4c29b907.js"><link rel="prefetch" href="/assets/js/7.e34ea00f.js"><link rel="prefetch" href="/assets/js/70.1b993ed4.js"><link rel="prefetch" href="/assets/js/71.e16ad4f9.js"><link rel="prefetch" href="/assets/js/72.627505e6.js"><link rel="prefetch" href="/assets/js/73.32768e14.js"><link rel="prefetch" href="/assets/js/74.968a580d.js"><link rel="prefetch" href="/assets/js/75.42d5af3d.js"><link rel="prefetch" href="/assets/js/76.19a69d31.js"><link rel="prefetch" href="/assets/js/77.cf627a78.js"><link rel="prefetch" href="/assets/js/78.07177880.js"><link rel="prefetch" href="/assets/js/8.c4dd00ce.js"><link rel="prefetch" href="/assets/js/9.0ff73be2.js">
    <link rel="stylesheet" href="/assets/css/0.styles.ada71c49.css">
  </head>
  <body class="theme-mode-light">
    <div id="app" data-server-rendered="true"><div class="theme-container sidebar-open have-rightmenu"><header class="navbar blur"><div title="目录" class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"><img src="/img/logo.png" alt="浪飞IT小栈" class="logo"> <span class="site-name can-hide">浪飞IT小栈</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/" class="nav-link">首页</a></div><div class="nav-item"><a href="/pages/6138ae/" class="nav-link">Java速通</a></div><div class="nav-item"><a href="/pages/705b35/" class="nav-link">面试经典</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="精品项目" class="dropdown-title"><a href="/project/" class="link-title">精品项目</a> <span class="title" style="display:none;">精品项目</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>桌面端</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/pages/8143cc480faf9a11/" class="nav-link">JavaScript</a></li></ul></li><li class="dropdown-item"><h4>PC后端</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/note/javascript/" class="nav-link">项目1</a></li><li class="dropdown-subitem"><a href="/note/typescript-axios/" class="nav-link">项目二</a></li></ul></li></ul></div></div><div class="nav-item"><a href="/about/" class="nav-link">电子书</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="索引" class="dropdown-title"><a href="/archives/" class="link-title">索引</a> <span class="title" style="display:none;">索引</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/categories/" class="nav-link">分类</a></li><li class="dropdown-item"><!----> <a href="/tags/" class="nav-link">标签</a></li><li class="dropdown-item"><!----> <a href="/archives/" class="nav-link">归档</a></li></ul></div></div><div class="nav-item"><a href="/pages/0c07b2/" class="nav-link">IT杂货铺</a></div><div class="nav-item"><a href="/archives/" class="nav-link">更多资源</a></div> <!----></nav></div></header> <div class="sidebar-mask"></div> <div class="sidebar-hover-trigger"></div> <aside class="sidebar" style="display:none;"><div class="blogger"><img src="https://cdn.jsdelivr.net/gh/langfeiyes/images-khub/avatar.jpg"> <div class="blogger-info"><h3>浪飞yes</h3> <span>无法简单的人儿~</span></div></div> <nav class="nav-links"><div class="nav-item"><a href="/" class="nav-link">首页</a></div><div class="nav-item"><a href="/pages/6138ae/" class="nav-link">Java速通</a></div><div class="nav-item"><a href="/pages/705b35/" class="nav-link">面试经典</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="精品项目" class="dropdown-title"><a href="/project/" class="link-title">精品项目</a> <span class="title" style="display:none;">精品项目</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><h4>桌面端</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/pages/8143cc480faf9a11/" class="nav-link">JavaScript</a></li></ul></li><li class="dropdown-item"><h4>PC后端</h4> <ul class="dropdown-subitem-wrapper"><li class="dropdown-subitem"><a href="/note/javascript/" class="nav-link">项目1</a></li><li class="dropdown-subitem"><a href="/note/typescript-axios/" class="nav-link">项目二</a></li></ul></li></ul></div></div><div class="nav-item"><a href="/about/" class="nav-link">电子书</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="索引" class="dropdown-title"><a href="/archives/" class="link-title">索引</a> <span class="title" style="display:none;">索引</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/categories/" class="nav-link">分类</a></li><li class="dropdown-item"><!----> <a href="/tags/" class="nav-link">标签</a></li><li class="dropdown-item"><!----> <a href="/archives/" class="nav-link">归档</a></li></ul></div></div><div class="nav-item"><a href="/pages/0c07b2/" class="nav-link">IT杂货铺</a></div><div class="nav-item"><a href="/archives/" class="nav-link">更多资源</a></div> <!----></nav>  <ul class="sidebar-links"><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>开篇</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>基础语法</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>面向对象</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>常用类</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>基础高级</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>数据库</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading open"><span>前端技术</span> <span class="arrow down"></span></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/pages/84c5d2/" class="sidebar-link">HTML与CSS</a></li><li><a href="/pages/42b6b6/" class="sidebar-link">JavaScript与DOM</a></li><li><a href="/pages/1125b7/" class="sidebar-link">网络编程与Tomcat</a></li><li><a href="/pages/be0e03/" class="sidebar-link">Http与Servlet</a></li><li><a href="/pages/9902e4/" class="sidebar-link">请求与响应</a></li><li><a href="/pages/18345f/" class="sidebar-link">JSP与EL与JSTL</a></li><li><a href="/pages/aa67fd/" class="sidebar-link">WEB版CRUD</a></li><li><a href="/pages/baec2f/" class="sidebar-link">Cookie与Session</a></li><li><a href="/pages/73e2cb/" class="sidebar-link">文件上传与下载和登录</a></li><li><a href="/pages/f99e33/" aria-current="page" class="active sidebar-link">项目实战-MIS系统</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level2"><a href="/pages/f99e33/#一、今日学习内容与目标" class="sidebar-link">一、今日学习内容与目标</a></li><li class="sidebar-sub-header level2"><a href="/pages/f99e33/#二、分页查询" class="sidebar-link">二、分页查询</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_2-1-分页查询" class="sidebar-link">2.1 分页查询</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_2-1-1-分页分类" class="sidebar-link">2.1.1 分页分类</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_2-1-2-分页效果" class="sidebar-link">2.1.2 分页效果</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_2-2-分页数据分析" class="sidebar-link">2.2 分页数据分析</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_2-2-1-分页需传递的参数" class="sidebar-link">2.2.1 分页需传递的参数</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_2-2-2-分页需展示的数据" class="sidebar-link">2.2.2 分页需展示的数据</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_2-2-3-分页需展示的数据的来源" class="sidebar-link">2.2.3 分页需展示的数据的来源</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_2-2-3-1-结果总条数与结果集-分页原理" class="sidebar-link">2.2.3.1 结果总条数与结果集（分页原理）</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_2-2-3-2-总页数、上一页和下一页" class="sidebar-link">2.2.3.2 总页数、上一页和下一页</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_2-3-分页查询实现" class="sidebar-link">2.3 分页查询实现</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_2-3-1-访问流程" class="sidebar-link">2.3.1 访问流程</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_2-3-2-分页数据封装" class="sidebar-link">2.3.2 分页数据封装</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_2-3-2-1-为什么要封装" class="sidebar-link">2.3.2.1 为什么要封装</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_2-3-2-2-编写-pageresult-java" class="sidebar-link">2.3.2.2 编写 PageResult.java</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_2-4-持久层分页功能实现" class="sidebar-link">2.4 持久层分页功能实现</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_2-4-1-修改-iproductdao-java" class="sidebar-link">2.4.1 修改 IProductDAO.java</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_2-4-2-编写-queryobject-java" class="sidebar-link">2.4.2 编写 QueryObject.java</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_2-4-3-再修改-iproductdao-java" class="sidebar-link">2.4.3 再修改 IProductDAO.java</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_2-4-4-修改-productdaoimpl-java" class="sidebar-link">2.4.4 修改 ProductDAOImpl.java</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_2-4-5-修改-productmapper-xml" class="sidebar-link">2.4.5 修改 ProductMapper.xml</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_2-4-6-修改-queryobjet-java" class="sidebar-link">2.4.6 修改 QueryObjet.java</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_2-4-7-编写单元测试" class="sidebar-link">2.4.7 编写单元测试</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_2-5-业务层分页功能实现" class="sidebar-link">2.5 业务层分页功能实现</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_2-5-1-编写-iproductservice-java" class="sidebar-link">2.5.1 编写 IProductService.java</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_2-5-2-编写-productserviceimpl-java" class="sidebar-link">2.5.2 编写 ProductServiceImpl.java</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_2-5-3-编写单元测试类" class="sidebar-link">2.5.3 编写单元测试类</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_2-6-前台分页功能实现" class="sidebar-link">2.6 前台分页功能实现</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_2-6-1-操作步骤" class="sidebar-link">2.6.1 操作步骤</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_2-6-2-修改-productservlet-java" class="sidebar-link">2.6.2 修改 ProductServlet.java</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_2-6-3-修改-list-jsp" class="sidebar-link">2.6.3 修改 list.jsp</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_2-7-常见问题" class="sidebar-link">2.7 常见问题</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_2-8-小结梳理" class="sidebar-link">2.8 小结梳理</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/pages/f99e33/#三、条件查询" class="sidebar-link">三、条件查询</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_3-1-条件查询" class="sidebar-link">3.1 条件查询</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-1-1-需求及效果图" class="sidebar-link">3.1.1 需求及效果图</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-1-2-原理分析" class="sidebar-link">3.1.2 原理分析</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-1-3-需解决的问题" class="sidebar-link">3.1.3 需解决的问题</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_3-2-条件数据封装" class="sidebar-link">3.2 条件数据封装</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_3-3-mybatis-动态-sql" class="sidebar-link">3.3 MyBatis 动态 SQL</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-3-1-if-标签" class="sidebar-link">3.3.1 if 标签</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_3-3-1-1-语法与作用" class="sidebar-link">3.3.1.1 语法与作用</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_3-3-1-2-需求应用" class="sidebar-link">3.3.1.2 需求应用</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_3-3-1-3-存在的问题" class="sidebar-link">3.3.1.3 存在的问题</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-3-2-where-标签" class="sidebar-link">3.3.2 where 标签</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_3-3-2-1-语法与作用" class="sidebar-link">3.3.2.1 语法与作用</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_3-3-2-2-需求应用" class="sidebar-link">3.3.2.2 需求应用</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-3-3-mybatis-转义符号" class="sidebar-link">3.3.3 MyBatis 转义符号</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_3-4-过滤查询实现" class="sidebar-link">3.4 过滤查询实现</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-4-1-编写-productqueryobject-java" class="sidebar-link">3.4.1 编写 ProductQueryObject.java</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-4-2-修改-productmapper-xml" class="sidebar-link">3.4.2 修改 ProductMapper.xml</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-4-3-修改-iproductdao-java-和-productdaoimpl" class="sidebar-link">3.4.3 修改 IProductDAO.java 和 ProductDAOImpl</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-4-4-修改-productserviceimpl" class="sidebar-link">3.4.4 修改 ProductServiceImpl</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-4-5-修改单元测试类" class="sidebar-link">3.4.5 修改单元测试类</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-4-6-修改-list-jsp" class="sidebar-link">3.4.6 修改 list.jsp</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-4-7-修改-productservlet-java" class="sidebar-link">3.4.7 修改 ProductServlet.java</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-4-8-查询条件回显" class="sidebar-link">3.4.8 查询条件回显</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-4-9-页面测试" class="sidebar-link">3.4.9 页面测试</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_3-5-细节说明" class="sidebar-link">3.5 细节说明</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-5-1-concat-函数" class="sidebar-link">3.5.1 concat 函数</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-5-2-productname-判断空的问题" class="sidebar-link">3.5.2 productName 判断空的问题</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_3-5-2-1-在-mapper-xml-中判断" class="sidebar-link">3.5.2.1 在 Mapper XML 中判断</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_3-5-2-2-在-java-代码中判断" class="sidebar-link">3.5.2.2 在 Java 代码中判断</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_3-6-翻页数据丢失问题" class="sidebar-link">3.6 翻页数据丢失问题</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-6-1-存在的问题" class="sidebar-link">3.6.1 存在的问题</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-6-2-问题原因" class="sidebar-link">3.6.2 问题原因</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-6-3-解决思路" class="sidebar-link">3.6.3 解决思路</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-6-4-代码实现" class="sidebar-link">3.6.4 代码实现</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_3-7-小结梳理" class="sidebar-link">3.7 小结梳理</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-7-1-分页过滤查询流程图" class="sidebar-link">3.7.1 分页过滤查询流程图</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_3-7-2-mapper-xml-中代码优化" class="sidebar-link">3.7.2 Mapper XML 中代码优化</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/pages/f99e33/#四、用户注销" class="sidebar-link">四、用户注销</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_4-1-修改-login-jsp" class="sidebar-link">4.1 修改 login.jsp</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_4-2-修改-list-jsp" class="sidebar-link">4.2 修改 list.jsp</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_4-3-编写-logoutservlet-java" class="sidebar-link">4.3 编写 LogoutServlet.java</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/pages/f99e33/#五、记住账号" class="sidebar-link">五、记住账号</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_5-1-修改-login-jsp" class="sidebar-link">5.1 修改 login.jsp</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_5-2-修改-loginservlet-java" class="sidebar-link">5.2 修改 LoginServlet.java</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_5-3-登录页面回显和记住账号" class="sidebar-link">5.3 登录页面回显和记住账号</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/pages/f99e33/#六-验证码" class="sidebar-link">六 验证码</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_6-1-作用" class="sidebar-link">6.1 作用</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_6-2-分类" class="sidebar-link">6.2 分类</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_6-3-图片验证码原理" class="sidebar-link">6.3 图片验证码原理</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_6-4-图片验证码实现" class="sidebar-link">6.4 图片验证码实现</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/pages/f99e33/#七-过滤器-filter" class="sidebar-link">七 过滤器 Filter</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_7-1-定义及应用" class="sidebar-link">7.1 定义及应用</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_7-2-filter-的-hello-world" class="sidebar-link">7.2 Filter 的 Hello World</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_7-2-1-回顾-servlet-开发步骤" class="sidebar-link">7.2.1 回顾 Servlet 开发步骤</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_7-2-2-helloservlet-代码演示" class="sidebar-link">7.2.2 HelloServlet 代码演示</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_7-2-2-1-编写-helloservlet-java" class="sidebar-link">7.2.2.1 编写 HelloServlet.java</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_7-2-2-2-配置-helloservlet" class="sidebar-link">7.2.2.2 配置 HelloServlet</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_7-2-2-3-编写-hello-jsp" class="sidebar-link">7.2.2.3 编写 hello.jsp</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_7-2-3-filter-开发步骤" class="sidebar-link">7.2.3 Filter 开发步骤</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_7-2-4-hellofilter-代码演示" class="sidebar-link">7.2.4 HelloFilter 代码演示</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_7-2-4-1-编写-hellofilter-java" class="sidebar-link">7.2.4.1 编写 HelloFilter.java</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_7-2-4-2-配置-hellofilter" class="sidebar-link">7.2.4.2 配置 HelloFilter</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_7-2-4-3-测试" class="sidebar-link">7.2.4.3 测试</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_7-3-过滤路径" class="sidebar-link">7.3 过滤路径</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_7-4-filter-的生命周期" class="sidebar-link">7.4 Filter 的生命周期</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_7-4-1-生命周期" class="sidebar-link">7.4.1 生命周期</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_7-4-2-代码验证" class="sidebar-link">7.4.2 代码验证</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_7-4-3-执行顺序" class="sidebar-link">7.4.3 执行顺序</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_7-5-filterchain-过滤器链" class="sidebar-link">7.5 FilterChain（过滤器链）</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_7-6-过滤方式-了解" class="sidebar-link">7.6 过滤方式（了解）</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_7-6-1-过滤转发" class="sidebar-link">7.6.1 过滤转发</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_7-6-2-过滤器错误" class="sidebar-link">7.6.2 过滤器错误</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_7-6-2-1-编写-404-jsp-和-500-jsp" class="sidebar-link">7.6.2.1 编写 404.jsp 和 500.jsp</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_7-6-2-2-配置通用的错误页面" class="sidebar-link">7.6.2.2 配置通用的错误页面</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_7-6-2-3-修改过滤器过滤方式" class="sidebar-link">7.6.2.3 修改过滤器过滤方式</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_7-7-字符编码过滤器" class="sidebar-link">7.7 字符编码过滤器</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_7-7-1-编码过滤器引入" class="sidebar-link">7.7.1 编码过滤器引入</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_7-7-2-代码实现" class="sidebar-link">7.7.2 代码实现</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_7-7-2-1-修改所有-servlet" class="sidebar-link">7.7.2.1 修改所有 Servlet</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_7-7-2-2-编写-characterencodingfilter-java" class="sidebar-link">7.7.2.2 编写 CharacterEncodingFilter.java</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_7-7-2-3-配置-characterencodingfilter" class="sidebar-link">7.7.2.3 配置 CharacterEncodingFilter</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_7-7-3-字符编码可以配置" class="sidebar-link">7.7.3 字符编码可以配置</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_7-7-3-1-配置字符编码" class="sidebar-link">7.7.3.1 配置字符编码</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_7-7-3-2-修改-characterencodingfilter-java" class="sidebar-link">7.7.3.2 修改 CharacterEncodingFilter.java</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_7-7-4-字符编码覆盖设置" class="sidebar-link">7.7.4 字符编码覆盖设置</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_7-7-4-1-配置字符编码是否覆盖" class="sidebar-link">7.7.4.1 配置字符编码是否覆盖</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_7-7-4-2-修改-characterencodingfilter-java" class="sidebar-link">7.7.4.2 修改 characterEncodingFilter.java</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_7-8-登录校验过滤器" class="sidebar-link">7.8 登录校验过滤器</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_7-8-1-登录校验过滤器引入" class="sidebar-link">7.8.1 登录校验过滤器引入</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_7-8-2-代码实现" class="sidebar-link">7.8.2 代码实现</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_7-8-2-1-修改所有-servlet" class="sidebar-link">7.8.2.1 修改所有 Servlet</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_7-8-2-2-编写-checkloginfilter-java" class="sidebar-link">7.8.2.2 编写 CheckLoginFilter.java</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_7-8-2-3-配置-checkloginfilter" class="sidebar-link">7.8.2.3 配置 CheckLoginFilter</a></li><li class="sidebar-sub-header level5"><a href="/pages/f99e33/#_7-8-2-4-匿名访问资源" class="sidebar-link">7.8.2.4 匿名访问资源</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/pages/f99e33/#八-监听器-listener" class="sidebar-link">八 监听器 Listener</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_8-1-监听什么及分类" class="sidebar-link">8.1 监听什么及分类</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_8-2-开发监听器的步骤" class="sidebar-link">8.2 开发监听器的步骤</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_8-3-统计游客数量" class="sidebar-link">8.3 统计游客数量</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_8-3-1-编写-visitorlistener-java" class="sidebar-link">8.3.1 编写 VisitorListener.java</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_8-3-2-配置-visitorlistener" class="sidebar-link">8.3.2 配置 VisitorListener</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_8-4-创建系统默认管理员" class="sidebar-link">8.4 创建系统默认管理员</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_8-4-1-思考的问题" class="sidebar-link">8.4.1 思考的问题</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_8-4-2-编写并配置-createsuperuserlistener" class="sidebar-link">8.4.2 编写并配置 CreateSuperUserListener</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_8-4-3-修改-iuserdao-和-userdaoimpl" class="sidebar-link">8.4.3 修改 IUserDAO 和 UserDAOImpl</a></li><li class="sidebar-sub-header level4"><a href="/pages/f99e33/#_8-4-4-修改-usermapper-xml" class="sidebar-link">8.4.4 修改 UserMapper.xml</a></li></ul></li><li class="sidebar-sub-header level2"><a href="/pages/f99e33/#九-页面美化-拓展" class="sidebar-link">九 页面美化（拓展）</a></li><li class="sidebar-sub-header level2"><a href="/pages/f99e33/#十、小结与作业" class="sidebar-link">十、小结与作业</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_10-1-小结" class="sidebar-link">10.1 小结</a></li><li class="sidebar-sub-header level3"><a href="/pages/f99e33/#_10-2-作业" class="sidebar-link">10.2 作业</a></li></ul></li></ul></li></ul></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>热门框架</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>前后端分离</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>权限控制</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>NoSQL</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>微服务</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>消息中间件</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>脚手架</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>技术增值</span> <span class="arrow right"></span></p> <!----></section></li></ul> </aside> <div><main class="page"><div class="theme-vdoing-wrapper "><div class="articleInfo-wrap" data-v-06225672><div class="articleInfo" data-v-06225672><ul class="breadcrumbs" data-v-06225672><li data-v-06225672><a href="/" title="首页" class="iconfont icon-home router-link-active" data-v-06225672></a></li> <li data-v-06225672><a href="/categories/?category=Java%E9%80%9F%E9%80%9A" title="分类" data-v-06225672>Java速通</a></li><li data-v-06225672><a href="/categories/?category=%E5%89%8D%E7%AB%AF%E6%8A%80%E6%9C%AF" title="分类" data-v-06225672>前端技术</a></li></ul> <div class="info" data-v-06225672><div title="作者" class="author iconfont icon-touxiang" data-v-06225672><a href="https://github.com/langfeiyes" target="_blank" title="作者" class="beLink" data-v-06225672>langfeiyes</a></div> <div title="创建时间" class="date iconfont icon-riqi" data-v-06225672><a href="javascript:;" data-v-06225672>2024-03-03</a></div> <!----></div></div></div> <!----> <div class="content-wrapper"><div class="right-menu-wrapper"><div class="right-menu-margin"><div class="right-menu-title">目录</div> <div class="right-menu-content"></div></div></div> <h1><img src="">项目实战-MIS系统<!----></h1>  <div class="theme-vdoing-content content__default"><h1 id="综合实战-mis系统"><a href="#综合实战-mis系统" class="header-anchor">#</a> 综合实战-MIS系统</h1> <h2 id="一、今日学习内容与目标"><a href="#一、今日学习内容与目标" class="header-anchor">#</a> 一、今日学习内容与目标</h2> <ul><li>了解分页查询的分类</li> <li>掌握分页的设计逻辑 (理解)</li> <li>掌握分页的代码实现</li> <li>了解常见的问题</li> <li>理解过滤查询的底层原理</li> <li>掌握 MyBatis 动态 SQL 常用标签的使用</li> <li>掌握 MyBatis 配置文件中的常用转义符</li> <li>掌握过滤查询的实现</li> <li>理解过滤查询使用到的 concat 函数</li> <li>掌握翻页数据丢失的解决方案</li> <li>理解用户注销的业务逻辑</li> <li>掌握用户注销实现</li> <li>理解验证码的原理</li> <li>通过文档完成验证码的实现</li> <li>理解 Filter 所处位置以及作用</li> <li>掌握字符编码过滤器的应用</li> <li>掌握登录过滤器的实现</li> <li>理解监听器的作用及分类</li> <li>掌握使用监听器创建系统默认管理员账号</li> <li>了解页面美化操作</li></ul> <h2 id="二、分页查询"><a href="#二、分页查询" class="header-anchor">#</a> 二、分页查询</h2> <h3 id="_2-1-分页查询"><a href="#_2-1-分页查询" class="header-anchor">#</a> 2.1 分页查询</h3> <p>分页查询则是在页面上将本来很多的数据分段显示，每页显示用户自定义的行数。可提高用户体验度，同时减少一次性加载，内存溢出风险。</p> <h4 id="_2-1-1-分页分类"><a href="#_2-1-1-分页分类" class="header-anchor">#</a> 2.1.1 分页分类</h4> <p>分页分为：真分页和假分页。</p> <ul><li><p><strong>假分页</strong>：一次性查询所有数据存入内存，翻页从内存中获取数据。</p> <p>​			优点：实现简单，性能高；缺点：容易造成内存溢出。</p></li> <li><p><strong>真分页</strong>：每次翻页从数据库中查询数据。</p> <p>​			优点：不容易造成内存溢出；缺点：实现复杂，性能相对低。</p></li></ul> <h4 id="_2-1-2-分页效果"><a href="#_2-1-2-分页效果" class="header-anchor">#</a> 2.1.2 分页效果</h4> <p>发送请求访问一个带有分页页面 (京东) 的数据，会发现其主要由两部分组成：</p> <ul><li>当前页的<strong>结果集</strong>数据，比如这一页有哪些商品信息。</li> <li><strong>分页条信息</strong>，比如包含【首页】【上页】【下页】【末页】等。</li></ul> <p>咱们的设计：</p> <p><img src="https://cdn.jsdelivr.net/gh/langfeiyes/images-khub/image-20200520072159365.png" alt="image-20200520072159365"></p> <h3 id="_2-2-分页数据分析"><a href="#_2-2-分页数据分析" class="header-anchor">#</a> 2.2 分页数据分析</h3> <p>从上面请求访问的分页效果图分析，分页功能需要哪些数据？</p> <h4 id="_2-2-1-分页需传递的参数"><a href="#_2-2-1-分页需传递的参数" class="header-anchor">#</a> 2.2.1 分页需传递的参数</h4> <p>需要用户传入的参数：</p> <ul><li>currentPage：当前页，跳转到第几页，int 类型，设置默认值，比如 1。</li> <li>pageSize：每页最多多少条数据，int 类型，设置默认值，比如 10。</li></ul> <h4 id="_2-2-2-分页需展示的数据"><a href="#_2-2-2-分页需展示的数据" class="header-anchor">#</a> 2.2.2 分页需展示的数据</h4> <p>从分页效果图中可以看出，分页需要依赖的数据：</p> <ul><li>当前页货品信息: data/list</li> <li>分页条信息：
<ul><li>beginPage：         首页</li> <li>prevPage：          上一页</li> <li>nextPage：          下一页</li> <li>totalPage：          总页数/末页</li> <li>totalCount/rows: 总条数</li> <li>currentPage：     当前页</li> <li>pageSize：           每页显示多少条数据</li></ul></li></ul> <h4 id="_2-2-3-分页需展示的数据的来源"><a href="#_2-2-3-分页需展示的数据的来源" class="header-anchor">#</a> 2.2.3 分页需展示的数据的来源</h4> <ul><li><p>来源于用户传入：</p> <ul><li>currentPage：     当前页，int 类型</li> <li>pageSize：        每页显示多少条数据，int 类型</li></ul></li> <li><p>来源于两条 SQL 查询：</p> <ul><li>totalCount/rows： 数据总条数，int 类型</li> <li>data/list：       每一页的结果集数据，List 类型</li></ul></li> <li><p>来源于程序计算：</p> <ul><li>totalPage：        总页数/末页，int 类型</li> <li>prevPage：        上一页，int 类型</li> <li>nextPage：        下一页，int 类型</li></ul></li></ul> <h5 id="_2-2-3-1-结果总条数与结果集-分页原理"><a href="#_2-2-3-1-结果总条数与结果集-分页原理" class="header-anchor">#</a> 2.2.3.1 结果总条数与结果集（分页原理）</h5> <p>结果总数（totalCount/rows）和结果集（data/list）是来源于两条 SQL（必须掌）的查询：</p> <ul><li><p><strong>第一条 SQL</strong>：查询符合条件的结果总数（totalCount/rows）</p> <div class="language-sql line-numbers-mode"><pre class="language-sql"><code><span class="token keyword">SELECT</span> <span class="token function">COUNT</span><span class="token punctuation">(</span><span class="token operator">*</span><span class="token punctuation">)</span> <span class="token keyword">FROM</span> 表名 <span class="token punctuation">[</span><span class="token keyword">WHERE</span> 条件<span class="token punctuation">]</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div></li> <li><p><strong>第二条 SQL</strong>：查询符合条件的结果集（data/list）</p> <div class="language-sql line-numbers-mode"><pre class="language-sql"><code><span class="token comment">## 第一个 ?：从哪一个索引的数据开始查询(默认从 0 开始)</span>
<span class="token comment">## 第二个 ?：查询多少条数据   </span>
<span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> 表名 <span class="token punctuation">[</span><span class="token keyword">WHERE</span> 条件<span class="token punctuation">]</span> <span class="token keyword">LIMIT</span> ?<span class="token punctuation">,</span> ?
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div></li></ul> <h5 id="_2-2-3-2-总页数、上一页和下一页"><a href="#_2-2-3-2-总页数、上一页和下一页" class="header-anchor">#</a> 2.2.3.2 总页数、上一页和下一页</h5> <p>总页数、上一页和下一页都是来源于程序计算出来的。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">int</span> totalPage <span class="token operator">=</span> rows <span class="token operator">%</span> pageSize <span class="token operator">==</span> <span class="token number">0</span> <span class="token operator">?</span> rows <span class="token operator">/</span> pageSize <span class="token operator">:</span> rows <span class="token operator">/</span> pageSize  <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span> <span class="token comment">// 优先计算</span>
<span class="token keyword">int</span> prevPage <span class="token operator">=</span> currentPage <span class="token operator">-</span> <span class="token number">1</span> <span class="token operator">&gt;=</span> <span class="token number">1</span> <span class="token operator">?</span> currentPage <span class="token operator">-</span> <span class="token number">1</span> <span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> nextPage <span class="token operator">=</span> currentPage <span class="token operator">+</span> <span class="token number">1</span> <span class="token operator">&lt;=</span> totalPage <span class="token operator">?</span> currentPage <span class="token operator">+</span> <span class="token number">1</span> <span class="token operator">:</span> totalPage<span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><h3 id="_2-3-分页查询实现"><a href="#_2-3-分页查询实现" class="header-anchor">#</a> 2.3 分页查询实现</h3> <p>给产品增加分页查询的功能。</p> <h4 id="_2-3-1-访问流程"><a href="#_2-3-1-访问流程" class="header-anchor">#</a> 2.3.1 访问流程</h4> <p><img src="https://cdn.jsdelivr.net/gh/langfeiyes/images-khub/image-20200520103702352.png" alt="image-20200520103702352"></p> <h4 id="_2-3-2-分页数据封装"><a href="#_2-3-2-分页数据封装" class="header-anchor">#</a> 2.3.2 分页数据封装</h4> <p>为了能在页面上显示上述的分页效果，那么我们就得在把页面上的每一个数据封装成到某个对象共享给 JSP。</p> <h5 id="_2-3-2-1-为什么要封装"><a href="#_2-3-2-1-为什么要封装" class="header-anchor">#</a> 2.3.2.1 为什么要封装</h5> <p>若不封装的话，会怎样，效果如下：</p> <p><img src="https://cdn.jsdelivr.net/gh/langfeiyes/images-khub/image-20200520073151772.png" alt="image-20200520073151772"></p> <p><strong>恶心</strong>：数据太分散，需要共享多个数据，不方便统一管理多个数据。
<strong>解决方案</strong>：把多个需要共享的数据，封装到一个对象，往后就只需要把数据封装到该对象，再共享该对象即可。</p> <h5 id="_2-3-2-2-编写-pageresult-java"><a href="#_2-3-2-2-编写-pageresult-java" class="header-anchor">#</a> 2.3.2.2 编写 PageResult.java</h5> <p>在之前 Web CRUD 项目的基础上增加新的代码即可。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">cn<span class="token punctuation">.</span>wolfcode<span class="token punctuation">.</span>qo</span><span class="token punctuation">;</span>

<span class="token comment">/**
 * 封装结果数据（某一页的数据）
 */</span>
<span class="token annotation punctuation">@Getter</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">PageResult</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> <span class="token punctuation">{</span>
    <span class="token comment">// 两个用户的输入</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> currentPage<span class="token punctuation">;</span>        <span class="token comment">// 当前页码</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> pageSize<span class="token punctuation">;</span>           <span class="token comment">// 每页显示的条数</span>
    <span class="token comment">// 两条 SQL 语句执行的结果</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> totalCount<span class="token punctuation">;</span>         <span class="token comment">// 总条数</span>
    <span class="token keyword">private</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> data<span class="token punctuation">;</span>           <span class="token comment">// 当前页结果集数据</span>
    <span class="token comment">// 三个程序计算的数据</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> prevPage<span class="token punctuation">;</span>           <span class="token comment">// 上一页页码</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> nextPage<span class="token punctuation">;</span>           <span class="token comment">// 下一页页码</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> totalPage<span class="token punctuation">;</span>          <span class="token comment">// 总页数/末页页码</span>

    <span class="token comment">// 分页数据通过下面构造期封装好，但思考一下这个构造器什么调用？</span>
    <span class="token keyword">public</span> <span class="token class-name">PageResult</span><span class="token punctuation">(</span><span class="token keyword">int</span> currentPage<span class="token punctuation">,</span> <span class="token keyword">int</span> pageSize<span class="token punctuation">,</span> <span class="token keyword">int</span> totalCount<span class="token punctuation">,</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span> data<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>currentPage <span class="token operator">=</span> currentPage<span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>pageSize <span class="token operator">=</span> pageSize<span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>totalCount <span class="token operator">=</span> totalCount<span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>data <span class="token operator">=</span> data<span class="token punctuation">;</span>

        <span class="token comment">// 计算三个数据</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>totalPage <span class="token operator">=</span> totalCount <span class="token operator">%</span> pageSize <span class="token operator">==</span> <span class="token number">0</span> <span class="token operator">?</span> totalCount <span class="token operator">/</span> pageSize <span class="token operator">:</span> totalCount <span class="token operator">/</span> pageSize <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>prevPage <span class="token operator">=</span> currentPage <span class="token operator">-</span> <span class="token number">1</span> <span class="token operator">&gt;=</span> <span class="token number">1</span> <span class="token operator">?</span> currentPage <span class="token operator">-</span> <span class="token number">1</span> <span class="token operator">:</span> <span class="token number">1</span><span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>nextPage <span class="token operator">=</span> currentPage <span class="token operator">+</span> <span class="token number">1</span> <span class="token operator">&lt;=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>totalPage <span class="token operator">?</span> currentPage <span class="token operator">+</span> <span class="token number">1</span> <span class="token operator">:</span> <span class="token keyword">this</span><span class="token punctuation">.</span>totalPage<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br></div></div><h3 id="_2-4-持久层分页功能实现"><a href="#_2-4-持久层分页功能实现" class="header-anchor">#</a> 2.4 持久层分页功能实现</h3> <p>分页其最终的所有功能需要依赖的 SQL 就两条：</p> <ul><li>查询数据的总数（为了显示分页条信息）。</li> <li>查询当前页的数据。
所以我们就得给 DAO 增加两个方法，一个查询数据总量，一个查询当前页的数据。</li></ul> <h4 id="_2-4-1-修改-iproductdao-java"><a href="#_2-4-1-修改-iproductdao-java" class="header-anchor">#</a> 2.4.1 修改 IProductDAO.java</h4> <p>给其增加两个方法，分别用于查询结果总数和结果集。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">int</span> <span class="token function">queryForCount</span><span class="token punctuation">(</span><span class="token keyword">int</span> currentPage<span class="token punctuation">,</span> <span class="token keyword">int</span> pageSize<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Product</span><span class="token punctuation">&gt;</span></span> <span class="token function">queryForList</span><span class="token punctuation">(</span><span class="token keyword">int</span> currentPage<span class="token punctuation">,</span> <span class="token keyword">int</span> pageSize<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>上述这样写的话方法是有两个形参的，但是 MyBatis 提供的操作方法传入执行 SQL 任务的参数，<strong>注意只能是一个</strong>，而现在两个参数需要传递两个分页的实参。
<img src="https://cdn.jsdelivr.net/gh/langfeiyes/images-khub/image-20200520074002652.png" alt="image-20200520074002652"></p> <p><strong>解决方案</strong>：
<strong>方案一</strong>：使用 Map 来封装需要传递的参数。
<strong>方案二</strong>：使用 JavaBean 来封装需要传递的参数。</p> <h4 id="_2-4-2-编写-queryobject-java"><a href="#_2-4-2-编写-queryobject-java" class="header-anchor">#</a> 2.4.2 编写 QueryObject.java</h4> <p>目前用来封装分页参数，并解决上面的问题。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">cn<span class="token punctuation">.</span>wolfcode<span class="token punctuation">.</span>qo</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Setter</span>
<span class="token annotation punctuation">@Getter</span>
<span class="token comment">/**
 * 封装分页查询需要的两个请求传入的分页参数
 */</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">QueryObject</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> currentPage <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>    <span class="token comment">// 当前页码，要跳转到哪一页的页码（需要给默认值）</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> pageSize <span class="token operator">=</span> <span class="token number">3</span><span class="token punctuation">;</span>       <span class="token comment">// 每页显示条数（需要给默认值）</span>
<span class="token punctuation">}</span>

</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><h4 id="_2-4-3-再修改-iproductdao-java"><a href="#_2-4-3-再修改-iproductdao-java" class="header-anchor">#</a> 2.4.3 再修改 IProductDAO.java</h4> <p>修改分页查询的两个方法，改方法形参为 QueryObject。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">int</span> <span class="token function">queryForCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Product</span><span class="token punctuation">&gt;</span></span> <span class="token function">queryForList</span><span class="token punctuation">(</span><span class="token class-name">QueryObject</span> qo<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><h4 id="_2-4-4-修改-productdaoimpl-java"><a href="#_2-4-4-修改-productdaoimpl-java" class="header-anchor">#</a> 2.4.4 修改 ProductDAOImpl.java</h4> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">queryForCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">SqlSession</span> session <span class="token operator">=</span> <span class="token class-name">MyBatisUtil</span><span class="token punctuation">.</span><span class="token function">getSession</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span> totalCount <span class="token operator">=</span> session<span class="token punctuation">.</span><span class="token function">selectOne</span><span class="token punctuation">(</span><span class="token string">&quot;cn.wolfcode.mapper.ProductMapper.queryForCount&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    session<span class="token punctuation">.</span><span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> totalCount<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">public</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Product</span><span class="token punctuation">&gt;</span></span> <span class="token function">queryForList</span><span class="token punctuation">(</span><span class="token class-name">QueryObject</span> qo<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">SqlSession</span> session <span class="token operator">=</span> <span class="token class-name">MyBatisUtil</span><span class="token punctuation">.</span><span class="token function">getSession</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Product</span><span class="token punctuation">&gt;</span></span> products <span class="token operator">=</span> session<span class="token punctuation">.</span><span class="token function">selectList</span><span class="token punctuation">(</span><span class="token string">&quot;cn.wolfcode.mapper.ProductMapper.queryForList&quot;</span><span class="token punctuation">,</span>qo<span class="token punctuation">)</span><span class="token punctuation">;</span>
    session<span class="token punctuation">.</span><span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> products<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br></div></div><h4 id="_2-4-5-修改-productmapper-xml"><a href="#_2-4-5-修改-productmapper-xml" class="header-anchor">#</a> 2.4.5 修改 ProductMapper.xml</h4> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>queryForCount<span class="token punctuation">&quot;</span></span> <span class="token attr-name">resultType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>int<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    SELECT COUNT(*) FROM product
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>select</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>queryForList<span class="token punctuation">&quot;</span></span> <span class="token attr-name">resultType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>cn.wolfcode.domain.Product<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    SELECT * FROM product LIMIT #{start}, #{pageSize}
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>select</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><h4 id="_2-4-6-修改-queryobjet-java"><a href="#_2-4-6-修改-queryobjet-java" class="header-anchor">#</a> 2.4.6 修改 QueryObjet.java</h4> <p>给 QueryObject 增加 getStart 方法，返回之前找出规律算出从那个位置开始查询数据，代码如下：</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">cn<span class="token punctuation">.</span>wolfcode<span class="token punctuation">.</span>qo</span><span class="token punctuation">;</span>

<span class="token keyword">import</span> <span class="token import"><span class="token namespace">lombok<span class="token punctuation">.</span></span><span class="token class-name">Getter</span></span><span class="token punctuation">;</span>
<span class="token keyword">import</span> <span class="token import"><span class="token namespace">lombok<span class="token punctuation">.</span></span><span class="token class-name">Setter</span></span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Setter</span>
<span class="token annotation punctuation">@Getter</span>
<span class="token comment">/**
 * 封装分页查询需要的两个请求传入的分页参数
 */</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">QueryObject</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> currentPage <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>    <span class="token comment">// 当前页码，要跳转到哪一页的页码（需要给默认值）</span>
    <span class="token keyword">private</span> <span class="token keyword">int</span> pageSize <span class="token operator">=</span> <span class="token number">3</span><span class="token punctuation">;</span>       <span class="token comment">// 每页显示条数（需要给默认值）</span>

    <span class="token comment">// 用于 Limit 子句第一个 ? 取值</span>
    <span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">getStart</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token punctuation">(</span>currentPage <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">)</span> <span class="token operator">*</span> pageSize<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br></div></div><h4 id="_2-4-7-编写单元测试"><a href="#_2-4-7-编写单元测试" class="header-anchor">#</a> 2.4.7 编写单元测试</h4> <p>给测试类 ProductDAOTest 中添加分页测试的方法，测试一下。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code> <span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testQueryForCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token class-name">QueryObject</span> qo <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">QueryObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>productDAO<span class="token punctuation">.</span><span class="token function">queryForCount</span><span class="token punctuation">(</span>qo<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testQueryForList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token class-name">QueryObject</span> qo<span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">QueryObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>productDAO<span class="token punctuation">.</span><span class="token function">queryForList</span><span class="token punctuation">(</span>qo<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br></div></div><h3 id="_2-5-业务层分页功能实现"><a href="#_2-5-业务层分页功能实现" class="header-anchor">#</a> 2.5 业务层分页功能实现</h3> <p>给 Servlet 调用，返回分页查询的结果，即返回 PageResult 对象，而形参类型为 QueryObject。</p> <h4 id="_2-5-1-编写-iproductservice-java"><a href="#_2-5-1-编写-iproductservice-java" class="header-anchor">#</a> 2.5.1 编写 IProductService.java</h4> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">cn<span class="token punctuation">.</span>wolfcode<span class="token punctuation">.</span>service</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">IProductService</span> <span class="token punctuation">{</span>
    <span class="token comment">/**
     * 完成查询某一页的业务逻辑功能
     */</span>
    <span class="token class-name">PageResult</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Product</span><span class="token punctuation">&gt;</span></span> <span class="token function">query</span><span class="token punctuation">(</span><span class="token class-name">QueryObject</span> qo<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><h4 id="_2-5-2-编写-productserviceimpl-java"><a href="#_2-5-2-编写-productserviceimpl-java" class="header-anchor">#</a> 2.5.2 编写 ProductServiceImpl.java</h4> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">cn<span class="token punctuation">.</span>wolfcode<span class="token punctuation">.</span>service<span class="token punctuation">.</span>impl</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ProductServiceImpl</span> <span class="token keyword">implements</span> <span class="token class-name">IProductService</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token class-name">IProductDAO</span> productDAO <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ProductDAOImpl</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token class-name">PageResult</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Product</span><span class="token punctuation">&gt;</span></span> <span class="token function">query</span><span class="token punctuation">(</span><span class="token class-name">QueryObject</span> qo<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 调用 DAO 查询数据数量</span>
        <span class="token keyword">int</span> totalCount <span class="token operator">=</span> productDAO<span class="token punctuation">.</span><span class="token function">queryForCount</span><span class="token punctuation">(</span>qo<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 为了性能加入判断，若查询的数据数量为 0，说明没有数据，返回返回空集合，即集合中没有元素</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span>totalCount <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
            <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">PageResult</span><span class="token punctuation">(</span>qo<span class="token punctuation">.</span><span class="token function">getCurrentPage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> qo<span class="token punctuation">.</span><span class="token function">getPageSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token comment">// 执行到这里代表有数据，查询当前页的结果数据</span>
        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Product</span><span class="token punctuation">&gt;</span></span> products <span class="token operator">=</span> productDAO<span class="token punctuation">.</span><span class="token function">queryForList</span><span class="token punctuation">(</span>qo<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">PageResult</span><span class="token punctuation">(</span>qo<span class="token punctuation">.</span><span class="token function">getCurrentPage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> qo<span class="token punctuation">.</span><span class="token function">getPageSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> totalCount<span class="token punctuation">,</span> products<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br></div></div><h4 id="_2-5-3-编写单元测试类"><a href="#_2-5-3-编写单元测试类" class="header-anchor">#</a> 2.5.3 编写单元测试类</h4> <p>在 test 目录下的 cn.wolfcode.service 包下新建 ProductServiceTest 测试类，测试上面 query 方法，观察控制台输出结果。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">cn<span class="token punctuation">.</span>wolfcode<span class="token punctuation">.</span>service</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ProductServiceTest</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token class-name">IProductService</span> productService <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ProductServiceImpl</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Test</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testQuery</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        <span class="token class-name">QueryObject</span> qo<span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">QueryObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        qo<span class="token punctuation">.</span><span class="token function">setCurrentPage</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">PageResult</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Product</span><span class="token punctuation">&gt;</span></span> pageResult <span class="token operator">=</span> productService<span class="token punctuation">.</span><span class="token function">query</span><span class="token punctuation">(</span>qo<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;结果集数据：&quot;</span> <span class="token operator">+</span> pageResult<span class="token punctuation">.</span><span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;当前页总记录数：&quot;</span> <span class="token operator">+</span> pageResult<span class="token punctuation">.</span><span class="token function">getTotalCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;条数：&quot;</span> <span class="token operator">+</span> pageResult<span class="token punctuation">.</span><span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;总页数：&quot;</span> <span class="token operator">+</span> pageResult<span class="token punctuation">.</span><span class="token function">getTotalPage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;上一页：&quot;</span> <span class="token operator">+</span> pageResult<span class="token punctuation">.</span><span class="token function">getPrevPage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;下一页：&quot;</span> <span class="token operator">+</span> pageResult<span class="token punctuation">.</span><span class="token function">getNextPage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br></div></div><h3 id="_2-6-前台分页功能实现"><a href="#_2-6-前台分页功能实现" class="header-anchor">#</a> 2.6 前台分页功能实现</h3> <p>包含编写 Servlet 及 JSP，Servlet 处理请求，调用业务方法，把查询到数据共享到 JSP 中，展示给用户看。</p> <h4 id="_2-6-1-操作步骤"><a href="#_2-6-1-操作步骤" class="header-anchor">#</a> 2.6.1 操作步骤</h4> <ul><li><strong>必须先完成业务层组件，保证后台测试通过</strong>。</li> <li>遵循 MVC 思想。</li> <li>浏览器发出分页请求参数（去往第几页/每页多少条数据），在 Servlet 中接收这些参数，并封装到 QueryObject 对象，调用 Service 中分页查询方法（query）。</li> <li>把得到的分页查询结果对象（PageResult）共享在请求作用域中，跳转到 JSP，显示即可。</li> <li>修改 JSP 页面，编写出分页条信息（分页条中的信息来源于 PageResult 对象）。</li></ul> <h4 id="_2-6-2-修改-productservlet-java"><a href="#_2-6-2-修改-productservlet-java" class="header-anchor">#</a> 2.6.2 修改 ProductServlet.java</h4> <p>ProductServlet，获取页面传递的分页参数，执行查询，将结果共享到请求作用域，请求转发回到 list.jsp 页面。</p> <p>注意暂时注释掉其他报错代码，因为目前产品业务类中只提供分页查询的方法。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">private</span> <span class="token class-name">IProductService</span> productService <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ProductServiceImpl</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

<span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">list</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> req<span class="token punctuation">,</span> <span class="token class-name">HttpServletResponse</span> resp<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">ServletException</span><span class="token punctuation">,</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span>
    <span class="token class-name">QueryObject</span> qo <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">QueryObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 获取请求参数 currentPage，并转型封装</span>
    <span class="token class-name">String</span> currentPage <span class="token operator">=</span> req<span class="token punctuation">.</span><span class="token function">getParameter</span><span class="token punctuation">(</span><span class="token string">&quot;currentPage&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token class-name">StringUtil</span><span class="token punctuation">.</span><span class="token function">hasLength</span><span class="token punctuation">(</span>currentPage<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        qo<span class="token punctuation">.</span><span class="token function">setCurrentPage</span><span class="token punctuation">(</span><span class="token class-name">Integer</span><span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span>currentPage<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token comment">// 获取请求参数 pageSize，并转型封装</span>
    <span class="token class-name">String</span> pageSize <span class="token operator">=</span> req<span class="token punctuation">.</span><span class="token function">getParameter</span><span class="token punctuation">(</span><span class="token string">&quot;pageSize&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token class-name">StringUtil</span><span class="token punctuation">.</span><span class="token function">hasLength</span><span class="token punctuation">(</span>pageSize<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        qo<span class="token punctuation">.</span><span class="token function">setPageSize</span><span class="token punctuation">(</span><span class="token class-name">Integer</span><span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span>pageSize<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 调用业务层方法来处理请求查询某一页数据</span>
    <span class="token class-name">PageResult</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Product</span><span class="token punctuation">&gt;</span></span> pageResult <span class="token operator">=</span> productService<span class="token punctuation">.</span><span class="token function">query</span><span class="token punctuation">(</span>qo<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 把数据共享给 list.jsp</span>
    req<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">&quot;pageResult&quot;</span><span class="token punctuation">,</span> pageResult<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 控制跳转到 list.jsp 页面</span>
    req<span class="token punctuation">.</span><span class="token function">getRequestDispatcher</span><span class="token punctuation">(</span><span class="token string">&quot;/WEB-INF/views/product/list.jsp&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forward</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span> resp<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br></div></div><h4 id="_2-6-3-修改-list-jsp"><a href="#_2-6-3-修改-list-jsp" class="header-anchor">#</a> 2.6.3 修改 list.jsp</h4> <p>在此 JSP 使用 JSTL + EL 获取后台共享到请求作用域中的数据，展示给用户看。</p> <div class="language-jsp line-numbers-mode"><pre class="language-text"><code>&lt;%@ page contentType=&quot;text/html;charset=UTF-8&quot; language=&quot;java&quot; %&gt;
&lt;%@ taglib prefix=&quot;c&quot; uri=&quot;http://java.sun.com/jsp/jstl/core&quot; %&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;产品列表&lt;/title&gt;
    &lt;script type=&quot;text/javascript&quot;&gt;
        // 原有省略...
        // 分页 JS
        function changePageSize() {
            document.forms[0].submit();
        }
    &lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;a href=&quot;/replaceImg.jsp&quot;&gt;&lt;img src=&quot;${USER_IN_SESSION.headImg}&quot; title=&quot;更换头像&quot;/&gt;&lt;/a&gt;&lt;br/&gt;
    &lt;a href=&quot;/product?cmd=input&quot;&gt;添加&lt;/a&gt;
    &lt;form action=&quot;/product&quot;&gt;
        &lt;table border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; width=&quot;80%&quot;&gt;
            &lt;tr&gt;
                &lt;th&gt;编号&lt;/th&gt;
                &lt;th&gt;货品名&lt;/th&gt;
                &lt;th&gt;分类编号&lt;/th&gt;
                &lt;th&gt;零售价&lt;/th&gt;
                &lt;th&gt;供应商&lt;/th&gt;
                &lt;th&gt;品牌&lt;/th&gt;
                &lt;th&gt;折扣&lt;/th&gt;
                &lt;th&gt;进货价&lt;/th&gt;
                &lt;th&gt;操作&lt;/th&gt;
            &lt;/tr&gt;
            &lt;c:forEach var=&quot;product&quot; items=&quot;${pageResult.data}&quot; varStatus=&quot;status&quot;&gt;
                &lt;tr class=&quot;trClassName&quot;&gt;
                    &lt;td&gt;${status.count}&lt;/td&gt;
                    &lt;td&gt;${product.productName}&lt;/td&gt;
                    &lt;td&gt;${product.dir_id}&lt;/td&gt;
                    &lt;td&gt;${product.salePrice}&lt;/td&gt;
                    &lt;td&gt;${product.supplier}&lt;/td&gt;
                    &lt;td&gt;${product.brand}&lt;/td&gt;
                    &lt;td&gt;${product.cutoff}&lt;/td&gt;
                    &lt;td&gt;${product.costPrice}&lt;/td&gt;
                    &lt;td&gt;
                        &lt;a href=&quot;/product?cmd=delete&amp;id=${product.id}&quot;&gt;删除&lt;/a&gt;
                        &lt;a href=&quot;/product?cmd=input&amp;id=${product.id}&quot;&gt;修改&lt;/a&gt;
                    &lt;/td&gt;
                &lt;/tr&gt;
            &lt;/c:forEach&gt;
            &lt;tr align=&quot;center&quot;&gt;
                &lt;td colspan=&quot;9&quot;&gt;
                    &lt;a href=&quot;/product?currentPage=1&quot;&gt;首页&lt;/a&gt;
                    &lt;a href=&quot;/product?currentPage=${pageResult.prevPage}&quot;&gt;上一页&lt;/a&gt;
                    &lt;a href=&quot;/product?currentPage=${pageResult.nextPage}&quot;&gt;下一页&lt;/a&gt;
                    &lt;a href=&quot;/product?currentPage=${pageResult.totalPage}&quot;&gt;尾页&lt;/a&gt;
                    当前第 ${pageResult.currentPage} / ${pageResult.totalPage} 页
                    一共 ${pageResult.totalCount} 条数据
                    跳转到&lt;input type=&quot;number&quot; onchange=&quot;changePageSize()&quot; name=&quot;currentPage&quot; value=&quot;${pageResult.currentPage}&quot; style=&quot;width: 60px;&quot;&gt;页
                    每页显示
                    &lt;select name=&quot;pageSize&quot; onchange=&quot;changePageSize()&quot;&gt;
                        &lt;option value=&quot;3&quot; ${pageResult.pageSize == 3 ? 'selected' : ''}&gt; 3 &lt;/option&gt;
                        &lt;option value=&quot;5&quot; ${pageResult.pageSize == 5 ? 'selected' : ''}&gt; 5 &lt;/option&gt;
                        &lt;option value=&quot;8&quot; ${pageResult.pageSize == 8 ? 'selected' : ''}&gt; 8 &lt;/option&gt;
                    &lt;/select&gt;条数据
                &lt;/td&gt;
            &lt;/tr&gt;
        &lt;/table&gt;
    &lt;/form&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br><span class="line-number">48</span><br><span class="line-number">49</span><br><span class="line-number">50</span><br><span class="line-number">51</span><br><span class="line-number">52</span><br><span class="line-number">53</span><br><span class="line-number">54</span><br><span class="line-number">55</span><br><span class="line-number">56</span><br><span class="line-number">57</span><br><span class="line-number">58</span><br><span class="line-number">59</span><br><span class="line-number">60</span><br><span class="line-number">61</span><br><span class="line-number">62</span><br><span class="line-number">63</span><br><span class="line-number">64</span><br><span class="line-number">65</span><br><span class="line-number">66</span><br></div></div><h3 id="_2-7-常见问题"><a href="#_2-7-常见问题" class="header-anchor">#</a> 2.7 常见问题</h3> <p><strong>疑惑理解</strong>：</p> <ul><li>currentPage，表示要显示某一页数据的页码，在程序中表示翻页要去往的页面，比如 curentPage = 3，表示要跳转到第 3 页。</li> <li>上一页，下一页，末页是在 PageResult 的构造器中已经计算好。</li></ul> <p><strong>常见问题</strong>：若刚开始翻页操作成功，但是翻几页之后就不能翻页了，只能重启 Tomcat 才可以翻页，但是操作几次又不能翻页了。问题原因：在 DAO 中没有关闭 SqlSession 对象释放资源。</p> <p><strong>Servlet 代码优化</strong>：</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">list</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">req2qo</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span> qo<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// ......</span>
<span class="token punctuation">}</span>

<span class="token comment">// 获取请求参数封装成对象</span>
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">req2qo</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> req<span class="token punctuation">,</span> <span class="token class-name">QueryObject</span> qo<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">String</span> currentPage <span class="token operator">=</span> req<span class="token punctuation">.</span><span class="token function">getParameter</span><span class="token punctuation">(</span><span class="token string">&quot;currentPage&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">String</span> pageSize <span class="token operator">=</span> req<span class="token punctuation">.</span><span class="token function">getParameter</span><span class="token punctuation">(</span><span class="token string">&quot;pageSize&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token class-name">StringUtil</span><span class="token punctuation">.</span><span class="token function">hasLength</span><span class="token punctuation">(</span>currentPage<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        qo<span class="token punctuation">.</span><span class="token function">setCurrentPage</span><span class="token punctuation">(</span><span class="token class-name">Integer</span><span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span>currentPage<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token class-name">StringUtil</span><span class="token punctuation">.</span><span class="token function">hasLength</span><span class="token punctuation">(</span>pageSize<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        qo<span class="token punctuation">.</span><span class="token function">setPageSize</span><span class="token punctuation">(</span><span class="token class-name">Integer</span><span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span>pageSize<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br></div></div><h3 id="_2-8-小结梳理"><a href="#_2-8-小结梳理" class="header-anchor">#</a> 2.8 小结梳理</h3> <p><img src="https://cdn.jsdelivr.net/gh/langfeiyes/images-khub/image-20211031151300640.png" alt="image-20211031151300640"></p> <h2 id="三、条件查询"><a href="#三、条件查询" class="header-anchor">#</a> 三、条件查询</h2> <h3 id="_3-1-条件查询"><a href="#_3-1-条件查询" class="header-anchor">#</a> 3.1 条件查询</h3> <p>条件查询实则是根据用户传入的条件进行数据的筛选查询，最终返回结果给用户。</p> <h4 id="_3-1-1-需求及效果图"><a href="#_3-1-1-需求及效果图" class="header-anchor">#</a> 3.1.1 需求及效果图</h4> <p>例如：在商品列表中，用户可以根据自己的需要，按照商品的名称和价格范围对商品进行查询。</p> <p><img src="https://cdn.jsdelivr.net/gh/langfeiyes/images-khub/image-20200521103914172.png" alt="image-20200521103914172"></p> <h4 id="_3-1-2-原理分析"><a href="#_3-1-2-原理分析" class="header-anchor">#</a> 3.1.2 原理分析</h4> <p>以上条件设计，后台需执行的 SQL 会有如下几种：</p> <ul><li><p>需求 1：查询所有货品信息。</p> <div class="language-sql line-numbers-mode"><pre class="language-sql"><code><span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> product
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div></li> <li><p>需求 2：查询货品名称包含某个字符串的货品信息，例如包含 M 的。</p> <div class="language-sql line-numbers-mode"><pre class="language-sql"><code><span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> product <span class="token keyword">WHERE</span> productName <span class="token operator">LIKE</span> <span class="token string">'%M%'</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div></li> <li><p>需求 3：查询货品零售价在某个价格以下的货品信息，例如销售价小于等于 500。</p> <div class="language-sql line-numbers-mode"><pre class="language-sql"><code><span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> product <span class="token keyword">WHERE</span> salePrice <span class="token operator">&lt;=</span> <span class="token number">500</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div></li> <li><p>需求 4：查询货品零售价在某个价格以上的货品信息，例如销售价大于等于 200。</p> <div class="language-sql line-numbers-mode"><pre class="language-sql"><code><span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> product <span class="token keyword">WHERE</span> salePrice <span class="token operator">&gt;=</span> <span class="token number">200</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div></li> <li><p>需求 5：查询零售价在某个区间的的货品信息，例如且销售价在 200 到 500 之间（包含）。</p> <div class="language-sql line-numbers-mode"><pre class="language-sql"><code><span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> product <span class="token keyword">WHERE</span> salePrice <span class="token operator">&gt;=</span> <span class="token number">200</span> <span class="token operator">AND</span> salePrice <span class="token operator">&lt;=</span> <span class="token number">500</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div></li> <li><p>需求 6：查询货品名称包含某个字符串且零售价在某个价格以上的货品信息，例如名称包含 M，且销售价大于等于 200。</p> <div class="language-sql line-numbers-mode"><pre class="language-sql"><code><span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> product <span class="token keyword">WHERE</span> productName <span class="token operator">LIKE</span> <span class="token string">'%M%'</span> <span class="token operator">AND</span> salePrice <span class="token operator">&gt;=</span> <span class="token number">200</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div></li> <li><p>需求 7：查询货品名称包含某个字符串且零售价在某个价格以下的货品信息，例如名称包含 M，且销售价小于等于 500。</p> <div class="language-sql line-numbers-mode"><pre class="language-sql"><code><span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> product <span class="token keyword">WHERE</span> productName <span class="token operator">LIKE</span> <span class="token string">'%M%'</span> <span class="token operator">AND</span> salePrice <span class="token operator">&lt;=</span> <span class="token number">500</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div></li></ul> <ul><li><p>需求 8：查询货品名称包含某个字符串且零售价在某个区间的的货品信息，例如名称包含 M，且销售价在 200 到 500 之间（包含）。</p> <div class="language-sql line-numbers-mode"><pre class="language-sql"><code><span class="token keyword">SELECT</span> <span class="token operator">*</span> <span class="token keyword">FROM</span> product <span class="token keyword">WHERE</span> productName <span class="token operator">LIKE</span> <span class="token string">'%M%'</span> <span class="token operator">AND</span>  salePrice <span class="token operator">&gt;=</span> <span class="token number">200</span> <span class="token operator">AND</span> salePrice <span class="token operator">&lt;=</span> <span class="token number">500</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div></li></ul> <p>从以上 SQL 分析，不管如何查询，SELECT * FROM product 这部分 SQL 是固定不变，变的地方就只是 WHERE 子句部分，而这个子句的变化，取决于用户在页面传递的查询参数。因此，<strong>过滤查询直白点说就是根据用户查询传递的参数，拼接 WHERE 条件，这就是过滤查询的底层原理</strong>。</p> <h4 id="_3-1-3-需解决的问题"><a href="#_3-1-3-需解决的问题" class="header-anchor">#</a> 3.1.3 需解决的问题</h4> <ul><li>如何封装用户传递到后台的请求参数（过滤条件数据）？</li> <li>如何根据用户传递的参数，在 Mapper XML 中拼接对应的 SQL？</li></ul> <p><strong>解决方案</strong>：第一个问题定义一个类封装数据即可。第二个问题使用 MyBaits 的动态 SQL 来解决。</p> <h3 id="_3-2-条件数据封装"><a href="#_3-2-条件数据封装" class="header-anchor">#</a> 3.2 条件数据封装</h3> <p><img src="https://cdn.jsdelivr.net/gh/langfeiyes/images-khub/image-20200521103904729.png" alt="image-20200521103904729"></p> <p>根据前面我们对多条件过滤查询的分析得知，用户过滤查询时，请求时可能会传递多个过滤条件的参数来查询对应的数据，又因为这些参数需要在后台多个层次之间进行传递（servlet---&gt;service---&gt;dao），所以为了方便参数传递，我们选择将这些参数封装到指定的对象中，然后在多层之间进行传递。</p> <p>编写 ProductQueryObject.java</p> <p>用来封装过滤查询的参数。但由于产品查询又想支持分页查询，又想支持过滤查询，所以使用 ProductQueryObject 来 继承 QueryObject，这样既可以封装分页查询的参数，又可以封装过滤查询的参数，且减少代码重复。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">cn<span class="token punctuation">.</span>wolfcode<span class="token punctuation">.</span>qo</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Setter</span>
<span class="token annotation punctuation">@Getter</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ProductQueryObject</span> <span class="token keyword">extends</span> <span class="token class-name">QueryObject</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> productName<span class="token punctuation">;</span>         <span class="token comment">// 商品名</span>
    <span class="token keyword">private</span> <span class="token class-name">BigDecimal</span> minSalePrice<span class="token punctuation">;</span>    <span class="token comment">// 最小销售价格</span>
    <span class="token keyword">private</span> <span class="token class-name">BigDecimal</span> maxSalePrice<span class="token punctuation">;</span>    <span class="token comment">// 最大销售价格</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><h3 id="_3-3-mybatis-动态-sql"><a href="#_3-3-mybatis-动态-sql" class="header-anchor">#</a> 3.3 MyBatis 动态 SQL</h3> <p>为了解决在 Mapper XML 中拼接 SQL 的问题，此处需要来学习 MyBatis 的动态 SQL.</p> <p><img src="https://cdn.jsdelivr.net/gh/langfeiyes/images-khub/image-20200521070415143.png" alt="image-20200521070415143"></p> <h4 id="_3-3-1-if-标签"><a href="#_3-3-1-if-标签" class="header-anchor">#</a> 3.3.1 if 标签</h4> <h5 id="_3-3-1-1-语法与作用"><a href="#_3-3-1-1-语法与作用" class="header-anchor">#</a> 3.3.1.1 语法与作用</h5> <p>用于单条件判断，一般用于判断是否符合某一查询条件。语法如下：</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>boolean 表达式<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>boolean 表达式：</p> <ul><li>可以写类似这样（productName != null）booolean 表达式。</li> <li>表达式中可以使用逻辑运算符，使用<code>小写 and，or</code>，但不可用 &amp;&amp;，||。</li></ul> <h5 id="_3-3-1-2-需求应用"><a href="#_3-3-1-2-需求应用" class="header-anchor">#</a> 3.3.1.2 需求应用</h5> <p>需求：查询货品名称包含某个字符且零售价在某个区间的所有货品信息，商品名、最小销售价格和最大销售价格可能传也可能没传。</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>queryForList<span class="token punctuation">&quot;</span></span> <span class="token attr-name">resultType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>cn.wolfcode.domain.Product<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    SELECT * FROM product 
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>productName != null and productName != ''<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
        WHERE productName LIKE concat('%', #{productName}, '%')
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>minSalePrice != null<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
        AND salePrice &gt;= #{minSalePrice}
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>maxSalePrice != null<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
        AND salePrice &lt;= #{maxSalePrice}
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
    LIMIT #{beginIndex}, #{pageSize}
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>select</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br></div></div><h5 id="_3-3-1-3-存在的问题"><a href="#_3-3-1-3-存在的问题" class="header-anchor">#</a> 3.3.1.3 存在的问题</h5> <ul><li>条件是可选的，可能传也可能没传，此时造成拼接的 SQL 出现语法问题.</li> <li>&lt; 报错，因为使用了 XML 的标签字符。</li></ul> <p><strong>解决方案</strong>：第一个问题使用 where 标签解决，第二个问题使用转义符解决。</p> <h4 id="_3-3-2-where-标签"><a href="#_3-3-2-where-标签" class="header-anchor">#</a> 3.3.2 where 标签</h4> <h5 id="_3-3-2-1-语法与作用"><a href="#_3-3-2-1-语法与作用" class="header-anchor">#</a> 3.3.2.1 语法与作用</h5> <p>用于在第一个条件语句之前加入 WHERE 关键字或者去除多余的 AND 或 OR 关键字，语法如下：</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>where</span><span class="token punctuation">&gt;</span></span>条件语句<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>where</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>注意：
若查询条件语句没有 WHERE 关键字，则自动在查询条件语句之前插入 WHERE；
若查询条件语句以 &quot;AND&quot; 或 &quot;OR&quot; 开头，则把第一个 AND 或 OR 使用 WHERE 关键字替换。</p> <h5 id="_3-3-2-2-需求应用"><a href="#_3-3-2-2-需求应用" class="header-anchor">#</a> 3.3.2.2 需求应用</h5> <p>需求：查询货品名称包含某个字符且零售价在某个区间的所有货品信息，关键字、最小销售价格和最大销售价格可能传也可能没传。</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>queryForList<span class="token punctuation">&quot;</span></span> <span class="token attr-name">resultType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>cn.wolfcode.domain.Product<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    SELECT * FROM product
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>where</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>productName != null and productName != ''<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
            AND productName LIKE concat('%', #{productName}, '%')
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>minSalePrice != null<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
            AND salePrice &gt;= #{minSalePrice}
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>maxSalePrice != null<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
            AND salePrice &lt;= #{maxSalePrice}
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>where</span><span class="token punctuation">&gt;</span></span>
    LIMIT #{beginIndex}, #{pageSize}
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>select</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br></div></div><h4 id="_3-3-3-mybatis-转义符号"><a href="#_3-3-3-mybatis-转义符号" class="header-anchor">#</a> 3.3.3 MyBatis 转义符号</h4> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token entity named-entity" title="&lt;">&amp;lt;</span>    &lt;  小于号
<span class="token entity named-entity" title="&gt;">&amp;gt;</span>    &gt;  大于号
<span class="token entity named-entity" title="&amp;">&amp;amp;</span>   &amp;  与符号
<span class="token entity named-entity" title="&amp;apos;">&amp;apos;</span>  '  单引号
<span class="token entity named-entity" title="&quot;">&amp;quot;</span>  &quot;  双引号
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>queryForList<span class="token punctuation">&quot;</span></span> <span class="token attr-name">resultType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>cn.wolfcode.domain.Product<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    SELECT * FROM product
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>where</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>productName != null and productName != ''<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
            AND productName LIKE concat('%', #{productName}, '%')
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>minSalePrice != null<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
            AND salePrice <span class="token entity named-entity" title="&gt;">&amp;gt;</span>= #{minSalePrice}
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>maxSalePrice != null<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
            AND salePrice <span class="token entity named-entity" title="&lt;">&amp;lt;</span>= #{maxSalePrice}
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>where</span><span class="token punctuation">&gt;</span></span>
    LIMIT #{beginIndex}, #{pageSize}
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>select</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br></div></div><h3 id="_3-4-过滤查询实现"><a href="#_3-4-过滤查询实现" class="header-anchor">#</a> 3.4 过滤查询实现</h3> <p>需求：查询货品名称包含某个字符串且零售价在某个区间的所有货品信息。</p> <h4 id="_3-4-1-编写-productqueryobject-java"><a href="#_3-4-1-编写-productqueryobject-java" class="header-anchor">#</a> 3.4.1 编写 ProductQueryObject.java</h4> <p>继承 QueryObject，用于封装查询产品过滤查询的参数值。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">cn<span class="token punctuation">.</span>wolfcode<span class="token punctuation">.</span>qo</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Setter</span>
<span class="token annotation punctuation">@Getter</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ProductQueryObject</span> <span class="token keyword">extends</span> <span class="token class-name">QueryObject</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> productName<span class="token punctuation">;</span>         <span class="token comment">// 商品名</span>
    <span class="token keyword">private</span> <span class="token class-name">BigDecimal</span> minSalePrice<span class="token punctuation">;</span>    <span class="token comment">// 最小销售价格</span>
    <span class="token keyword">private</span> <span class="token class-name">BigDecimal</span> maxSalePrice<span class="token punctuation">;</span>    <span class="token comment">// 最大销售价格</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><p>注意：一般的为了避免不必要的麻烦，让字段名称和表单中的请求参数名称相同。</p> <h4 id="_3-4-2-修改-productmapper-xml"><a href="#_3-4-2-修改-productmapper-xml" class="header-anchor">#</a> 3.4.2 修改 ProductMapper.xml</h4> <p>拼接查询的 SQL 语句，查询结果总数和查询结果集都要拼接，且查询条件是一样的。</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>queryForCount<span class="token punctuation">&quot;</span></span> <span class="token attr-name">resultType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>int<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    SELECT COUNT(*) FROM product
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>where</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>productName != null and productName != ''<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
            AND productName LIKE concat('%', #{productName}, '%')
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>minSalePrice != null<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
            AND salePrice <span class="token entity named-entity" title="&gt;">&amp;gt;</span>= #{minSalePrice}
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>maxSalePrice != null<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
            AND salePrice <span class="token entity named-entity" title="&lt;">&amp;lt;</span>= #{maxSalePrice}
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>where</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>select</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>queryForList<span class="token punctuation">&quot;</span></span> <span class="token attr-name">resultType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>cn.wolfcode.domain.Product<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    SELECT * FROM product
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>where</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>productName != null and productName != ''<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
            AND productName LIKE concat('%', #{productName}, '%')
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>minSalePrice != null<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
            AND salePrice <span class="token entity named-entity" title="&gt;">&amp;gt;</span>= #{minSalePrice}
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>maxSalePrice != null<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
            AND salePrice <span class="token entity named-entity" title="&lt;">&amp;lt;</span>= #{maxSalePrice}
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>where</span><span class="token punctuation">&gt;</span></span>
    LIMIT #{beginIndex}, #{pageSize}
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>select</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br></div></div><h4 id="_3-4-3-修改-iproductdao-java-和-productdaoimpl"><a href="#_3-4-3-修改-iproductdao-java-和-productdaoimpl" class="header-anchor">#</a> 3.4.3 修改 IProductDAO.java 和 ProductDAOImpl</h4> <p>由于之前做分页时,查询总条件是没有加入条件的,而过滤查询是需要根据条件来查询满足条件的数据条数,所有需要修改查询总条数的方法.</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">IProductDAO</span> <span class="token punctuation">{</span>
	<span class="token comment">/**
     * 查询[满足条件]的总条数
     * @return 查询到的总条数 select count 返回的结果数据类型是long
     */</span>
    <span class="token keyword">int</span> <span class="token function">queryForCount</span><span class="token punctuation">(</span><span class="token class-name">QueryObject</span> qo<span class="token punctuation">)</span><span class="token punctuation">;</span>
    
    <span class="token comment">// 其他省略...</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ProductDAOImpl</span> <span class="token keyword">implements</span> <span class="token class-name">IProductDAO</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">queryForCount</span><span class="token punctuation">(</span><span class="token class-name">QueryObject</span> qo<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">SqlSession</span> session <span class="token operator">=</span> <span class="token class-name">MyBatisUtil</span><span class="token punctuation">.</span><span class="token function">openSession</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">int</span> totalCount <span class="token operator">=</span> session<span class="token punctuation">.</span><span class="token function">selectOne</span><span class="token punctuation">(</span><span class="token string">&quot;cn.wolfcode.webcrud.mapper.ProductMapper.queryForCount&quot;</span><span class="token punctuation">,</span>qo<span class="token punctuation">)</span><span class="token punctuation">;</span>
        session<span class="token punctuation">.</span><span class="token function">commit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        session<span class="token punctuation">.</span><span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> totalCount<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token comment">// 其他省略...</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><h4 id="_3-4-4-修改-productserviceimpl"><a href="#_3-4-4-修改-productserviceimpl" class="header-anchor">#</a> 3.4.4 修改 ProductServiceImpl</h4> <p>修改 productDAO.queryForCount() 方法的调用,带入条件参数去查询满足条件的总条数</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ProductServiceImpl</span> <span class="token keyword">implements</span> <span class="token class-name">IProductService</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token class-name">PageResult</span> <span class="token function">query</span><span class="token punctuation">(</span><span class="token class-name">QueryObject</span> qo<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">int</span> totalCount <span class="token operator">=</span> productDAO<span class="token punctuation">.</span><span class="token function">queryForCount</span><span class="token punctuation">(</span>qo<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 当总条数为0 时,不需要去查询列表数据</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>totalCount <span class="token operator">&lt;=</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">PageResult</span><span class="token punctuation">(</span>qo<span class="token punctuation">.</span><span class="token function">getCurrentPage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>qo<span class="token punctuation">.</span><span class="token function">getPageSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token comment">// 说明有数据</span>
        <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Product</span><span class="token punctuation">&gt;</span></span> list <span class="token operator">=</span> productDAO<span class="token punctuation">.</span><span class="token function">queryForList</span><span class="token punctuation">(</span>qo<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token class-name">PageResult</span><span class="token punctuation">(</span>qo<span class="token punctuation">.</span><span class="token function">getCurrentPage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>qo<span class="token punctuation">.</span><span class="token function">getPageSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>list<span class="token punctuation">,</span>totalCount<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><h4 id="_3-4-5-修改单元测试类"><a href="#_3-4-5-修改单元测试类" class="header-anchor">#</a> 3.4.5 修改单元测试类</h4> <p>造一些差异化的数据，修改 ProductServiceTest.java 其中 testQuery 方法，测试过滤查询，看是否有问题，最好每个条件都试一下。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Test</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">testQuery</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token class-name">ProductQueryObject</span> qo<span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ProductQueryObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    qo<span class="token punctuation">.</span><span class="token function">setCurrentPage</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    
    qo<span class="token punctuation">.</span><span class="token function">setProductName</span><span class="token punctuation">(</span><span class="token string">&quot;M&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    qo<span class="token punctuation">.</span><span class="token function">setMinSalePrice</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">BigDecimal</span><span class="token punctuation">(</span><span class="token string">&quot;200&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    qo<span class="token punctuation">.</span><span class="token function">setMaxSalePrice</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">BigDecimal</span><span class="token punctuation">(</span><span class="token string">&quot;500&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">PageResult</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Product</span><span class="token punctuation">&gt;</span></span> pageResult <span class="token operator">=</span> productService<span class="token punctuation">.</span><span class="token function">query</span><span class="token punctuation">(</span>qo<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;结果集数据：&quot;</span> <span class="token operator">+</span> pageResult<span class="token punctuation">.</span><span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;当前页总记录数：&quot;</span> <span class="token operator">+</span> pageResult<span class="token punctuation">.</span><span class="token function">getTotalCount</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;条数：&quot;</span> <span class="token operator">+</span> pageResult<span class="token punctuation">.</span><span class="token function">getData</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">size</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;总页数：&quot;</span> <span class="token operator">+</span> pageResult<span class="token punctuation">.</span><span class="token function">getTotalPage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;上一页：&quot;</span> <span class="token operator">+</span> pageResult<span class="token punctuation">.</span><span class="token function">getPrevPage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;下一页：&quot;</span> <span class="token operator">+</span> pageResult<span class="token punctuation">.</span><span class="token function">getNextPage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br></div></div><h4 id="_3-4-6-修改-list-jsp"><a href="#_3-4-6-修改-list-jsp" class="header-anchor">#</a> 3.4.6 修改 list.jsp</h4> <p>在 form 中增加过滤查询条件 input 元素，包含可以输入商品名，最小销售价，最大销售价，注意：让该表单（form）包含列表的 table 元素。</p> <div class="language-jsp line-numbers-mode"><pre class="language-text"><code>&lt;form action=&quot;/product&quot; method=&quot;post&quot;&gt;
        货品名:&lt;input type=&quot;text&quot; name=&quot;productName&quot; style=&quot;width: 80px;&quot;&gt;
        价格: &lt;input type=&quot;number&quot; name=&quot;minSalePrice&quot; style=&quot;width: 80px&quot;&gt; -
            &lt;input type=&quot;number&quot; name=&quot;maxSalePrice&quot; style=&quot;width: 80px;&quot;&gt;
            &lt;input type=&quot;submit&quot; value=&quot;查询&quot;&gt;
        &lt;table border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; width=&quot;80%&quot;&gt;
            &lt;!-- 省略 --&gt;
    &lt;/table&gt;
&lt;/form&gt;
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><h4 id="_3-4-7-修改-productservlet-java"><a href="#_3-4-7-修改-productservlet-java" class="header-anchor">#</a> 3.4.7 修改 ProductServlet.java</h4> <p>在调用业务对象的 query 方法之前，获取过滤查询参数，并封装到 ProductQueryObject 对象中。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">list</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> req<span class="token punctuation">,</span> <span class="token class-name">HttpServletResponse</span> resp<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">ServletException</span><span class="token punctuation">,</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span>
    <span class="token class-name">ProductQueryObject</span> qo <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ProductQueryObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// 获取请求参数 productName</span>
    <span class="token class-name">String</span> productName <span class="token operator">=</span> req<span class="token punctuation">.</span><span class="token function">getParameter</span><span class="token punctuation">(</span><span class="token string">&quot;productName&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    qo<span class="token punctuation">.</span><span class="token function">setProductName</span><span class="token punctuation">(</span>productName<span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// 获取请求参数 minSalePrice</span>
    <span class="token class-name">String</span> minSalePrice <span class="token operator">=</span> req<span class="token punctuation">.</span><span class="token function">getParameter</span><span class="token punctuation">(</span><span class="token string">&quot;minSalePrice&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token class-name">StringUtil</span><span class="token punctuation">.</span><span class="token function">hasLength</span><span class="token punctuation">(</span>minSalePrice<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        qo<span class="token punctuation">.</span><span class="token function">setMinSalePrice</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">BigDecimal</span><span class="token punctuation">(</span>minSalePrice<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 获取请求参数 maxSalePrice</span>
    <span class="token class-name">String</span> maxSalePrice <span class="token operator">=</span> req<span class="token punctuation">.</span><span class="token function">getParameter</span><span class="token punctuation">(</span><span class="token string">&quot;maxSalePrice&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token class-name">StringUtil</span><span class="token punctuation">.</span><span class="token function">hasLength</span><span class="token punctuation">(</span>maxSalePrice<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
        qo<span class="token punctuation">.</span><span class="token function">setMaxSalePrice</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">BigDecimal</span><span class="token punctuation">(</span>maxSalePrice<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    
    <span class="token comment">// 获取请求参数 currentPage</span>
    <span class="token class-name">String</span> currentPage <span class="token operator">=</span> req<span class="token punctuation">.</span><span class="token function">getParameter</span><span class="token punctuation">(</span><span class="token string">&quot;currentPage&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token class-name">StringUtil</span><span class="token punctuation">.</span><span class="token function">hasLength</span><span class="token punctuation">(</span>currentPage<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        qo<span class="token punctuation">.</span><span class="token function">setCurrentPage</span><span class="token punctuation">(</span><span class="token class-name">Integer</span><span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span>currentPage<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 获取请求参数 pageSize</span>
    <span class="token class-name">String</span> pageSize <span class="token operator">=</span> req<span class="token punctuation">.</span><span class="token function">getParameter</span><span class="token punctuation">(</span><span class="token string">&quot;pageSize&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token class-name">StringUtil</span><span class="token punctuation">.</span><span class="token function">hasLength</span><span class="token punctuation">(</span>pageSize<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        qo<span class="token punctuation">.</span><span class="token function">setPageSize</span><span class="token punctuation">(</span><span class="token class-name">Integer</span><span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span>pageSize<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 调用业务层方法来处理请求某一页数据的需求</span>
    <span class="token class-name">PageResult</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Product</span><span class="token punctuation">&gt;</span></span> pageResult <span class="token operator">=</span> productService<span class="token punctuation">.</span><span class="token function">query</span><span class="token punctuation">(</span>qo<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 把数据共享给 list.jsp</span>
    req<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">&quot;pageResult&quot;</span><span class="token punctuation">,</span> pageResult<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 控制跳转到 list.jsp 页面</span>
    req<span class="token punctuation">.</span><span class="token function">getRequestDispatcher</span><span class="token punctuation">(</span><span class="token string">&quot;/WEB-INF/views/product/list.jsp&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forward</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span> resp<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br></div></div><h4 id="_3-4-8-查询条件回显"><a href="#_3-4-8-查询条件回显" class="header-anchor">#</a> 3.4.8 查询条件回显</h4> <p>修改 ProductServlet.java，在跳转 list.jsp 前加入如下代码：</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">// 把查询参数数据共享给 list.jsp</span>
req<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">&quot;qo&quot;</span><span class="token punctuation">,</span> qo<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>修改 list.jsp，使之支持回显出查询的信息：</p> <div class="language-jsp line-numbers-mode"><pre class="language-text"><code>&lt;form action=&quot;/product&quot; method=&quot;post&quot;&gt;
        货品名:&lt;input type=&quot;text&quot; name=&quot;productName&quot; style=&quot;width: 80px;&quot; value=&quot;${qo.productName}&quot;&gt;
        价格: &lt;input type=&quot;number&quot; name=&quot;minSalePrice&quot; style=&quot;width: 80px&quot; value=&quot;${qo.minSalePrice}&quot;&gt; -
            &lt;input type=&quot;number&quot; name=&quot;maxSalePrice&quot; style=&quot;width: 80px;&quot; value=&quot;${qo.maxSalePrice}&quot;&gt;
            &lt;input type=&quot;submit&quot; value=&quot;查询&quot;&gt;
        &lt;table border=&quot;1&quot; cellspacing=&quot;0&quot; cellpadding=&quot;0&quot; width=&quot;80%&quot;&gt;
            &lt;!-- 省略 --&gt;
    &lt;/table&gt;
&lt;/form&gt;
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><h4 id="_3-4-9-页面测试"><a href="#_3-4-9-页面测试" class="header-anchor">#</a> 3.4.9 页面测试</h4> <p>每个条件都要测试到，保证在网页上测试通过。</p> <h3 id="_3-5-细节说明"><a href="#_3-5-细节说明" class="header-anchor">#</a> 3.5 细节说明</h3> <h4 id="_3-5-1-concat-函数"><a href="#_3-5-1-concat-函数" class="header-anchor">#</a> 3.5.1 concat 函数</h4> <p>MySQL 中 concat 函数是用来拼接字符串，项目模糊查询时会使用这个函数，与 % 进行拼接完成模糊查询的需求。-</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token comment">&lt;!-- 其中 if 标签 和 #{} 中的 productName 指 ProductQueryObject 的属性名 --&gt;</span>
<span class="token comment">&lt;!-- AND 后面的 productName 是 product 表中列明 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>productName != null and productName != ''<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    AND productName LIKE concat('%', #{productName}, '%')
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><h4 id="_3-5-2-productname-判断空的问题"><a href="#_3-5-2-productname-判断空的问题" class="header-anchor">#</a> 3.5.2 productName 判断空的问题</h4> <p>productName 属性是字符串类型，用户查询的时候，可能没传此参数或者传的是空字符串，所以我们需要在拼接条件之前进行判断，若用户查询传的是非空且有内容的的字符串时，才按照此条件过滤查询商品信息。</p> <p>而判断方式可以有以下几种：</p> <h5 id="_3-5-2-1-在-mapper-xml-中判断"><a href="#_3-5-2-1-在-mapper-xml-中判断" class="header-anchor">#</a> 3.5.2.1 在 Mapper XML 中判断</h5> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>productName != null and productName != ''<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    AND productName LIKE concat('%', #{productName}, '%')
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><h5 id="_3-5-2-2-在-java-代码中判断"><a href="#_3-5-2-2-在-java-代码中判断" class="header-anchor">#</a> 3.5.2.2 在 Java 代码中判断</h5> <p>因为 MyBatis 通过调用查询对象中的 getProductName() 方法，获取到 productName 属性值，然后再做判断的。所以我们可以在把查询对象中的 getProductName() 方法重写，在 MyBatis 获取 productName 属性值之前加入判断。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">cn<span class="token punctuation">.</span>wolfcode<span class="token punctuation">.</span>qo</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@Setter</span>
<span class="token annotation punctuation">@Getter</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ProductQueryObject</span> <span class="token keyword">extends</span> <span class="token class-name">QueryObject</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> productName<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">BigDecimal</span> minSalePrice<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token class-name">BigDecimal</span> maxSalePrice<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">getProductName</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token class-name">StringUtil</span><span class="token punctuation">.</span><span class="token function">hasLength</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>productName<span class="token punctuation">)</span> <span class="token operator">?</span> <span class="token keyword">this</span><span class="token punctuation">.</span>productName <span class="token operator">:</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br></div></div><p>那么在 Mapper XML 中此时就不需要再做空字符串的判断了只须像下面这样写即可。</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>productName != null<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    AND productName LIKE concat('%', #{productName}, '%')
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><h3 id="_3-6-翻页数据丢失问题"><a href="#_3-6-翻页数据丢失问题" class="header-anchor">#</a> 3.6 翻页数据丢失问题</h3> <h4 id="_3-6-1-存在的问题"><a href="#_3-6-1-存在的问题" class="header-anchor">#</a> 3.6.1 存在的问题</h4> <p>当通过过滤查询出结果集时，如下图：查询条件货品名输入的是 M，执行查询返回如下结果：</p> <p><img src="https://cdn.jsdelivr.net/gh/langfeiyes/images-khub/image-20200521114449731.png" alt="image-20200521114449731"></p> <p>但之后如果再点击下一页：应该是进入 2/5 页，可是结果却是如下这样的：</p> <p><img src="https://cdn.jsdelivr.net/gh/langfeiyes/images-khub/image-20200521114526247.png" alt="image-20200521114526247"></p> <p>此时，我们会发现过滤查询条件已经丢失，分页条的数据也全部和预期不一样了。</p> <h4 id="_3-6-2-问题原因"><a href="#_3-6-2-问题原因" class="header-anchor">#</a> 3.6.2 问题原因</h4> <p>此时的翻页操作（点击首页，上一页，下一页，尾页等这些操作），是通过 a 标签的超链接 发送 GET 请求查询，该超链接只带有 currentPage 参数，没带有其他过滤查询条件参数。</p> <div class="language-jsp line-numbers-mode"><pre class="language-text"><code>&lt;a href=&quot;/product?currentPage=1&quot;&gt;首页&lt;/a&gt;
&lt;a href=&quot;/product?currentPage=${pageResult.prevPage}&quot;&gt;上一页&lt;/a&gt;
&lt;a href=&quot;/product?currentPage=${pageResult.nextPage}&quot;&gt;下一页&lt;/a&gt;
&lt;a href=&quot;/product?currentPage=${pageResult.totalPage}&quot;&gt;尾页&lt;/a&gt;
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><h4 id="_3-6-3-解决思路"><a href="#_3-6-3-解决思路" class="header-anchor">#</a> 3.6.3 解决思路</h4> <p>在翻页的时候，不仅要发送 currentPage 到后台，同时还需要把过滤查询的参数发送到后台。解决方案：</p> <ul><li>在超链接上拼接过滤查询的参数，若参数过多，实现比较麻烦。</li> <li>使用 JS 来实现翻页操作，将超链接上的分页相关的参数放到表单中（推荐方式）。
<ul><li>在高级查询表单中提供 currentPage 的文本框，我们把需要跳转的页码设置到该文本框。</li> <li>再使用 JS 提交过滤查询表单，此时就可以把查询条件和 currentPage 一起提交到后台，并封装到   ProductQueryObject中。</li></ul></li></ul> <h4 id="_3-6-4-代码实现"><a href="#_3-6-4-代码实现" class="header-anchor">#</a> 3.6.4 代码实现</h4> <p><strong>修改 list.jsp</strong>：</p> <div class="language-jsp line-numbers-mode"><pre class="language-text"><code>&lt;!-- 加了 id 属性，目的为了方便通过 JS 获取标签对象重新设置 value 属性值 --&gt;
跳转到&lt;input type=&quot;number&quot; id=&quot;currentPageId&quot; onchange=&quot;changePageSize()&quot; name=&quot;currentPage&quot; value=&quot;${pageResult.currentPage}&quot; style=&quot;width: 60px;&quot;&gt;页
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><div class="language-jsp line-numbers-mode"><pre class="language-text"><code>&lt;a href=&quot;#&quot; onclick=&quot;goPage(1);&quot;&gt;首页&lt;/a&gt;
&lt;a href=&quot;#&quot; onclick=&quot;goPage(${pageResult.prevPage});&quot;&gt;上一页&lt;/a&gt;
&lt;a href=&quot;#&quot; onclick=&quot;goPage(${pageResult.nextPage});&quot;&gt;下一页&lt;/a&gt;
&lt;a href=&quot;#&quot; onclick=&quot;goPage(${pageResult.totalPage});&quot;&gt;尾页&lt;/a&gt;
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token keyword">function</span> <span class="token function">goPage</span><span class="token punctuation">(</span><span class="token parameter">pageNum</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 把pageNum 设置给表单中表示跳转到某一页的表单控件中</span>
    document<span class="token punctuation">.</span><span class="token function">getElementById</span><span class="token punctuation">(</span><span class="token string">&quot;currentPageId&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span>value <span class="token operator">=</span> pageNum<span class="token punctuation">;</span>
    <span class="token comment">// 提交表单数据</span>
    document<span class="token punctuation">.</span>forms<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">submit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token comment">// 数据修改之后提交表单</span>
<span class="token keyword">function</span> <span class="token function">changePageSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token comment">// 提交表单数据</span>
    document<span class="token punctuation">.</span>forms<span class="token punctuation">[</span><span class="token number">0</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">submit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><h3 id="_3-7-小结梳理"><a href="#_3-7-小结梳理" class="header-anchor">#</a> 3.7 小结梳理</h3> <h4 id="_3-7-1-分页过滤查询流程图"><a href="#_3-7-1-分页过滤查询流程图" class="header-anchor">#</a> 3.7.1 分页过滤查询流程图</h4> <p><img src="https://cdn.jsdelivr.net/gh/langfeiyes/images-khub/pagefilterflow.png" alt="image-20200521144040176"></p> <h4 id="_3-7-2-mapper-xml-中代码优化"><a href="#_3-7-2-mapper-xml-中代码优化" class="header-anchor">#</a> 3.7.2 Mapper XML 中代码优化</h4> <p>抽取重复 SQL 的片段（模板），供其他 SQL 包含。</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token comment">&lt;!-- 抽取一个 SQL 片段 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>sql</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>where_sql<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>where</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>productName != null and productName != ''<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
            AND productName LIKE concat('%', #{productName}, '%')
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>minSalePrice != null<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
            AND salePrice <span class="token entity named-entity" title="&gt;">&amp;gt;</span>= #{minSalePrice}
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>if</span> <span class="token attr-name">test</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>maxSalePrice != null<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
            AND salePrice <span class="token entity named-entity" title="&lt;">&amp;lt;</span>= #{maxSalePrice}
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>if</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>where</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>sql</span><span class="token punctuation">&gt;</span></span>

<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>queryForCount<span class="token punctuation">&quot;</span></span> <span class="token attr-name">resultType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>int<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    SELECT COUNT(*) FROM product
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>include</span> <span class="token attr-name">refid</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>where_sql<span class="token punctuation">&quot;</span></span><span class="token punctuation">/&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>select</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>select</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>queryForList<span class="token punctuation">&quot;</span></span> <span class="token attr-name">resultType</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>cn.wolfcode.domain.Product<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    SELECT * FROM product
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>include</span> <span class="token attr-name">refid</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>where_sql<span class="token punctuation">&quot;</span></span><span class="token punctuation">/&gt;</span></span>
    LIMIT #{start}, #{pageSize}
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>select</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br></div></div><h2 id="四、用户注销"><a href="#四、用户注销" class="header-anchor">#</a> 四、用户注销</h2> <p>用户注销则为退出登录状态，将当前登录的用户信息销毁。而我们之前做的用户登录功能，是把当前登录用户信息是存在 session 中的，所以只需要清除 session 中的用户信息即可实现用户注销。</p> <h3 id="_4-1-修改-login-jsp"><a href="#_4-1-修改-login-jsp" class="header-anchor">#</a> 4.1 修改 login.jsp</h3> <p>为了登录页面好看，加入新的登录页面，按照给的<strong>资料\模板页面</strong>目录里面去拷贝即可（login.jsp，css 目录，js 目录）。</p> <p><img src="https://cdn.jsdelivr.net/gh/langfeiyes/images-khub/image_20200717105950.png" alt="image_20200717105950"><br></p> <h3 id="_4-2-修改-list-jsp"><a href="#_4-2-修改-list-jsp" class="header-anchor">#</a> 4.2 修改 list.jsp</h3> <p>修改产品的 list.jsp，提供给用户点击可以安全退出的链接，点击发送请求交由 Servlet 去处理。</p> <div class="language-jsp line-numbers-mode"><pre class="language-text"><code>欢迎：${USER_IN_SESSION.username} &lt;a href=&quot;/logout&quot;&gt; 安全退出&lt;/a&gt;&lt;br/&gt;
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><h3 id="_4-3-编写-logoutservlet-java"><a href="#_4-3-编写-logoutservlet-java" class="header-anchor">#</a> 4.3 编写 LogoutServlet.java</h3> <p>处理安全退出的请求，清除 session 中用户的登录信息，并重定到 login.jsp。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">cn<span class="token punctuation">.</span>wolfcode<span class="token punctuation">.</span>web<span class="token punctuation">.</span>servlet</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@WebServlet</span><span class="token punctuation">(</span><span class="token string">&quot;/logout&quot;</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">LogoutServlet</span> <span class="token keyword">extends</span> <span class="token class-name">HttpServlet</span> <span class="token punctuation">{</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">service</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> req<span class="token punctuation">,</span> <span class="token class-name">HttpServletResponse</span> resp<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">ServletException</span><span class="token punctuation">,</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span>
        <span class="token comment">// 方式一：删除用户共享数据</span>
        <span class="token comment">// req.getSession().removeAttribute(&quot;USER_IN_SESSION&quot;);</span>
        
        <span class="token comment">// 方式二：销毁整个 Session 对象</span>
        req<span class="token punctuation">.</span><span class="token function">getSession</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">invalidate</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        resp<span class="token punctuation">.</span><span class="token function">sendRedirect</span><span class="token punctuation">(</span><span class="token string">&quot;/login.jsp&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br></div></div><h2 id="五、记住账号"><a href="#五、记住账号" class="header-anchor">#</a> 五、记住账号</h2> <p>为了提升用户体验，在用户登录的时候可以选择记住账号信息，在指定时间范围内可以不用再重新填写账户信息。
因为需要将用户信息保存一段时间，放 session 的话浏览器关闭则会失效，所以选择使用 Cookie 来实现。</p> <h3 id="_5-1-修改-login-jsp"><a href="#_5-1-修改-login-jsp" class="header-anchor">#</a> 5.1 修改 login.jsp</h3> <p>提供勾选记住我复选框，点击登录时会传递参数 remeberMe 给 LoginServlet。</p> <div class="language-jsp line-numbers-mode"><pre class="language-text"><code>&lt;label&gt;
    &lt;!-- 为了方便后台转换，value 加上勾选后的值为 true ，默认勾选值为 on --&gt;
    &lt;input type=&quot;checkbox&quot; name=&quot;remeberMe&quot; value=&quot;true&quot;&gt; 记住我
&lt;/label&gt;
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><h3 id="_5-2-修改-loginservlet-java"><a href="#_5-2-修改-loginservlet-java" class="header-anchor">#</a> 5.2 修改 LoginServlet.java</h3> <p>获取请求参数 remeberMe，若是选中（true），创建 Cookie，指定时间并响应给浏览器；若没有选中，清除 Cookie 对象。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Override</span>
<span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">service</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> req<span class="token punctuation">,</span> <span class="token class-name">HttpServletResponse</span> resp<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">ServletException</span><span class="token punctuation">,</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span>
    req<span class="token punctuation">.</span><span class="token function">setCharacterEncoding</span><span class="token punctuation">(</span><span class="token string">&quot;UTF-8&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 接受请求参数</span>
    <span class="token class-name">String</span> username <span class="token operator">=</span> req<span class="token punctuation">.</span><span class="token function">getParameter</span><span class="token punctuation">(</span><span class="token string">&quot;username&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">String</span> password <span class="token operator">=</span> req<span class="token punctuation">.</span><span class="token function">getParameter</span><span class="token punctuation">(</span><span class="token string">&quot;password&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">try</span> <span class="token punctuation">{</span>
        <span class="token comment">// 调用业务方法来处理登录请求</span>
        <span class="token class-name">User</span> user <span class="token operator">=</span> userService<span class="token punctuation">.</span><span class="token function">login</span><span class="token punctuation">(</span>username<span class="token punctuation">,</span> password<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 登录成功时往 Session 中加入一个登录成功的标识，给其它需要登录才可以操作的资源做判断使用</span>
        req<span class="token punctuation">.</span><span class="token function">getSession</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">&quot;USER_IN_SESSION&quot;</span><span class="token punctuation">,</span> user<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token comment">//============== 是否记住我 ===============</span>
        <span class="token keyword">boolean</span> remeberMe <span class="token operator">=</span> <span class="token class-name">Boolean</span><span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span>req<span class="token punctuation">.</span><span class="token function">getParameter</span><span class="token punctuation">(</span><span class="token string">&quot;remeberMe&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Cookie</span> cookie <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Cookie</span><span class="token punctuation">(</span><span class="token string">&quot;username&quot;</span><span class="token punctuation">,</span> username<span class="token punctuation">)</span><span class="token punctuation">;</span>
        cookie<span class="token punctuation">.</span><span class="token function">setPath</span><span class="token punctuation">(</span><span class="token string">&quot;/&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span> <span class="token punctuation">(</span>remeberMe<span class="token punctuation">)</span><span class="token punctuation">{</span>
            <span class="token comment">// 设置 Cookie 有效时间为一周</span>
            cookie<span class="token punctuation">.</span><span class="token function">setMaxAge</span><span class="token punctuation">(</span><span class="token number">60</span> <span class="token operator">*</span> <span class="token number">60</span> <span class="token operator">*</span> <span class="token number">24</span> <span class="token operator">*</span> <span class="token number">7</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span><span class="token keyword">else</span><span class="token punctuation">{</span>
            <span class="token comment">// 删除 Cookie</span>
            cookie<span class="token punctuation">.</span><span class="token function">setMaxAge</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        resp<span class="token punctuation">.</span><span class="token function">addCookie</span><span class="token punctuation">(</span>cookie<span class="token punctuation">)</span><span class="token punctuation">;</span>
        
        <span class="token comment">// 控制跳转</span>
        resp<span class="token punctuation">.</span><span class="token function">sendRedirect</span><span class="token punctuation">(</span><span class="token string">&quot;/product&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span><span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span><span class="token punctuation">{</span> <span class="token comment">// 有异常时表示登录失败</span>
        e<span class="token punctuation">.</span><span class="token function">printStackTrace</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        req<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">&quot;errorMsg&quot;</span><span class="token punctuation">,</span> e<span class="token punctuation">.</span><span class="token function">getMessage</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        req<span class="token punctuation">.</span><span class="token function">getRequestDispatcher</span><span class="token punctuation">(</span><span class="token string">&quot;/login.jsp&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forward</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span> resp<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br></div></div><h3 id="_5-3-登录页面回显和记住账号"><a href="#_5-3-登录页面回显和记住账号" class="header-anchor">#</a> 5.3 登录页面回显和记住账号</h3> <p>修改 login.jsp 使用 EL 表达式回显账号和记住我。</p> <div class="language-jsp line-numbers-mode"><pre class="language-text"><code>&lt;input type=&quot;text&quot; class=&quot;form-control&quot; placeholder=&quot;请输入账号&quot; name=&quot;username&quot; value=&quot;${cookie.username.value}&quot;&gt;
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><div class="language-jsp line-numbers-mode"><pre class="language-text"><code>&lt;label&gt;
    &lt;input type=&quot;checkbox&quot; name=&quot;remeberMe&quot; value=&quot;true&quot;
        ${cookie.username.value != null ? 'checked' : ''}&gt; 记住我
&lt;/label&gt;
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><h2 id="六-验证码"><a href="#六-验证码" class="header-anchor">#</a> 六 验证码</h2> <h3 id="_6-1-作用"><a href="#_6-1-作用" class="header-anchor">#</a> 6.1 作用</h3> <p>验证码（CAPTCHA）是 “Completely Automated Public Turing test to tell Computers and Humans Apart”（<strong>全自动区分计算机和人类的图灵测试</strong>）的缩写，是一种<strong>区分用户是计算机还是人的公共全自动程序</strong>。可以<strong>防止：恶意破解密码、刷票、论坛灌水，有效防止黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登录尝试</strong>，实际上用验证码是现在很多网站通行的方式，我们利用比较简易的方式实现了这个功能。这个问题可以由计算机生成并评判，但是必须只有人类才能解答。由于计算机无法解答 CAPTCHA 的问题，所以回答出问题的用户就可以被认为是人类。</p> <h3 id="_6-2-分类"><a href="#_6-2-分类" class="header-anchor">#</a> 6.2 分类</h3> <ul><li>图片验证码（最常用）</li> <li>手机短信验证码。</li> <li>手机语音验证码。</li> <li>视频验证码。</li></ul> <h3 id="_6-3-图片验证码原理"><a href="#_6-3-图片验证码原理" class="header-anchor">#</a> 6.3 图片验证码原理</h3> <p>图片验证码功能分三个部分：</p> <ul><li>A 程序生成随机内容的验证码图片展现给用户。</li> <li>用户根据图片输入验证码文本。</li> <li>B 程序判断用户输入的验证码和 A 程序生成的验证码是否相同。</li></ul> <p><strong>问题</strong>：生成验证码的程序 A 和判断用户填写验证码的程序 B 不是同一个，如何在程序 B 中获取到程序 A 生成的验证码文本做判断？</p> <p><strong>解决</strong>：因为两个程序我们都是使用 Servlet 来实现的，所以可以把 A 程序生成 验证码之后存入 Session ，B 程序从 Session 中来获取。</p> <p><img src="https://cdn.jsdelivr.net/gh/langfeiyes/images-khub/image-20200523105513181.png" alt="image-20200523105513181"> <img src="https://cdn.jsdelivr.net/gh/langfeiyes/images-khub/image-20200523013222295.png" alt="image-20200523013222295"></p> <h3 id="_6-4-图片验证码实现"><a href="#_6-4-图片验证码实现" class="header-anchor">#</a> 6.4 图片验证码实现</h3> <p>需求：防止恶意登录，给登录加上验证码。</p> <p><strong>拷贝 RandomCodeServlet.java</strong></p> <p>这个负责生成图片验证码，并把验证码存在 Session 中。</p> <p><strong>修改在 login.jsp</strong></p> <p>提供 img 标签，显示验证码。</p> <div class="language-jsp line-numbers-mode"><pre class="language-text"><code>&lt;div class=&quot;row&quot;&gt;
    &lt;div class=&quot;col-xs-8&quot;&gt;
        &lt;input type=&quot;text&quot; class=&quot;form-control&quot; placeholder=&quot;请输入验证码&quot; name=&quot;randomCode&quot;&gt;
    &lt;/div&gt;
    &lt;div class=&quot;col-xs-4&quot;&gt;
        &lt;img style=&quot;width: 85px; height: 30px;&quot; alt=&quot;验证码&quot; src=&quot;/randomCode&quot;&gt;
    &lt;/div&gt;
&lt;/div&gt;
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><p><strong>修改 LoginServlet.java</strong></p> <p>加入验证码判断。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Override</span>
<span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">service</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> req<span class="token punctuation">,</span> <span class="token class-name">HttpServletResponse</span> resp<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">ServletException</span><span class="token punctuation">,</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span>
    req<span class="token punctuation">.</span><span class="token function">setCharacterEncoding</span><span class="token punctuation">(</span><span class="token string">&quot;UTF-8&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token comment">// 接受请求参数</span>
    <span class="token class-name">String</span> username <span class="token operator">=</span> req<span class="token punctuation">.</span><span class="token function">getParameter</span><span class="token punctuation">(</span><span class="token string">&quot;username&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">String</span> password <span class="token operator">=</span> req<span class="token punctuation">.</span><span class="token function">getParameter</span><span class="token punctuation">(</span><span class="token string">&quot;password&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// 判断验证码是否正确</span>
    <span class="token class-name">String</span> randomCode <span class="token operator">=</span> req<span class="token punctuation">.</span><span class="token function">getParameter</span><span class="token punctuation">(</span><span class="token string">&quot;randomCode&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">String</span> sessionRandomCode <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">)</span> req<span class="token punctuation">.</span><span class="token function">getSession</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">&quot;RANDOMCODE_IN_SESSION&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token operator">!</span><span class="token punctuation">(</span><span class="token class-name">StringUtil</span><span class="token punctuation">.</span><span class="token function">hasLength</span><span class="token punctuation">(</span>randomCode<span class="token punctuation">)</span>
            <span class="token operator">&amp;&amp;</span> <span class="token class-name">StringUtil</span><span class="token punctuation">.</span><span class="token function">hasLength</span><span class="token punctuation">(</span>sessionRandomCode<span class="token punctuation">)</span>
            <span class="token operator">&amp;&amp;</span> randomCode<span class="token punctuation">.</span><span class="token function">equalsIgnoreCase</span><span class="token punctuation">(</span>sessionRandomCode<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 跳回登录页面重新填写验证码</span>
        req<span class="token punctuation">.</span><span class="token function">setAttribute</span><span class="token punctuation">(</span><span class="token string">&quot;errorMsg&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;验证码错误&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        req<span class="token punctuation">.</span><span class="token function">getRequestDispatcher</span><span class="token punctuation">(</span><span class="token string">&quot;/login.jsp&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forward</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span> resp<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">return</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token comment">// 说明验证码正确，可以做登录校验，可以把验证码清除，验证码仅限于一次登录使用</span>
    req<span class="token punctuation">.</span><span class="token function">getSession</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">removeAttribute</span><span class="token punctuation">(</span><span class="token string">&quot;RANDOMCODE_IN_SESSION&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    
    <span class="token comment">// 后面登录操作省略 ......</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br></div></div><p><strong>修改验证码</strong></p> <p>生成的图片验证码可能存在用户识别不了的情况，可提供点击更换图片验证码功能。</p> <p><strong>思路</strong>: 当 img 标签的 src 属性值改变了，浏览器会自动发送新的请求。那么我们就给图片添加一个点击事件处理，点击了图片，修改该图片 src 的值即可，重新请求验证码图片。</p> <p>修改 login.jsp：</p> <div class="language-jsp line-numbers-mode"><pre class="language-text"><code>&lt;!-- 为图片绑定一个点击事件 --&gt;
&lt;img id=&quot;randomCode&quot; style=&quot;width: 85px; height: 30px; cursor: pointer&quot; alt=&quot;验证码&quot; src=&quot;/randomCode&quot; onclick=&quot;changeImg(this)&quot;&gt;
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><div class="language-js line-numbers-mode"><pre class="language-js"><code><span class="token comment">// 点击图片执行下面的函数</span>
<span class="token keyword">function</span> <span class="token function">changeImg</span><span class="token punctuation">(</span><span class="token parameter">imgEl</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 修改验证码 img 标签的 src 属性值，为什么要带参数，禁用浏览器缓存</span>
    imgEl<span class="token punctuation">.</span>src<span class="token operator">=</span><span class="token string">&quot;/randomCode?&quot;</span> <span class="token operator">+</span> <span class="token keyword">new</span> <span class="token class-name">Date</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getTime</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>浏览器有缓存，将 get 请求的结果缓存到本地磁盘，若请求相同的资源，不再发送新的请求，而是直接使用缓存中的结果。我们可以通过携带参数不一样来欺骗浏览器我们请求的资源不是同一个资源（实际上是同一个)。</p> <h2 id="七-过滤器-filter"><a href="#七-过滤器-filter" class="header-anchor">#</a> 七 过滤器 Filter</h2> <h3 id="_7-1-定义及应用"><a href="#_7-1-定义及应用" class="header-anchor">#</a> 7.1 定义及应用</h3> <p>Filter 是 Servlet 2.3 新增加的功能，Java Web 组件之一。<strong>使用户可以改变一个 request 和修改一个 response</strong>。Filter 不是一个 Servlet，它不能产生一个 response，它能够在一个 request 到达 Servlet 之前预处理 request，也可以在 response 离开 Servlet 后处理 response。换种说法，Filter 其实是一个 &quot;Servlet chaining&quot;（Servlet 链）。</p> <p><img src="https://cdn.jsdelivr.net/gh/langfeiyes/images-khub/image-20200523020233204.png" alt="image-20200523020233204"></p> <p>过滤器使用场景：</p> <ul><li>字符编码处理。</li> <li>登录校验。</li> <li>论坛敏感字过滤。</li> <li>做前端框架的分发器。</li></ul> <h3 id="_7-2-filter-的-hello-world"><a href="#_7-2-filter-的-hello-world" class="header-anchor">#</a> 7.2 Filter 的 Hello World</h3> <h4 id="_7-2-1-回顾-servlet-开发步骤"><a href="#_7-2-1-回顾-servlet-开发步骤" class="header-anchor">#</a> 7.2.1 回顾 Servlet 开发步骤</h4> <p>回顾 Servlet 开发步骤，类比有助于学习 Filter，步骤如下：</p> <ul><li>定义类，并实现 javax.servlet.Servlet 接口。</li> <li>覆写其中的 5 个方法，在 service 方法中编写处理请求做响应的代码。</li> <li>将写好的 Servlet 交给 Tomcat 来管理（XML/注解）。</li></ul> <h4 id="_7-2-2-helloservlet-代码演示"><a href="#_7-2-2-helloservlet-代码演示" class="header-anchor">#</a> 7.2.2 HelloServlet 代码演示</h4> <p>为了给大家更清楚地演示访问的执行流程，也写一个 HelloServlet。</p> <h5 id="_7-2-2-1-编写-helloservlet-java"><a href="#_7-2-2-1-编写-helloservlet-java" class="header-anchor">#</a> 7.2.2.1 编写 HelloServlet.java</h5> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">cn<span class="token punctuation">.</span>wolfcode<span class="token punctuation">.</span>web<span class="token punctuation">.</span>servlet</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">HelloServlet</span> <span class="token keyword">extends</span> <span class="token class-name">HttpServlet</span> <span class="token punctuation">{</span>
    <span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token function">service</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span> req<span class="token punctuation">,</span> <span class="token class-name">HttpServletResponse</span> resp<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">ServletException</span><span class="token punctuation">,</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;helloServlet&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        req<span class="token punctuation">.</span><span class="token function">getRequestDispatcher</span><span class="token punctuation">(</span><span class="token string">&quot;/hello.jsp&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">forward</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span>resp<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><h5 id="_7-2-2-2-配置-helloservlet"><a href="#_7-2-2-2-配置-helloservlet" class="header-anchor">#</a> 7.2.2.2 配置 HelloServlet</h5> <p>使用 XML 配置，在 web.xml 配置如下：</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>servlet</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>servlet-name</span><span class="token punctuation">&gt;</span></span>helloServlet<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>servlet-name</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>servlet-class</span><span class="token punctuation">&gt;</span></span> cn.wolfcode.web.servlet.HelloServlet<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>servlet-class</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>servlet</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>servlet-mapping</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>servlet-name</span><span class="token punctuation">&gt;</span></span>helloServlet<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>servlet-name</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>url-pattern</span><span class="token punctuation">&gt;</span></span>/hello<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>url-pattern</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>servlet-mapping</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><h5 id="_7-2-2-3-编写-hello-jsp"><a href="#_7-2-2-3-编写-hello-jsp" class="header-anchor">#</a> 7.2.2.3 编写 hello.jsp</h5> <p>在 web 目录下新建 hello.jsp，内容如下：</p> <div class="language-jsp line-numbers-mode"><pre class="language-text"><code>&lt;%@ page contentType=&quot;text/html;charset=UTF-8&quot; language=&quot;java&quot; %&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;title&gt;hello&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    欢迎
&lt;/body&gt;
&lt;/html&gt;
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><h4 id="_7-2-3-filter-开发步骤"><a href="#_7-2-3-filter-开发步骤" class="header-anchor">#</a> 7.2.3 Filter 开发步骤</h4> <p>Filter 也是一个 Java Web 组件之一，所以开发步骤和 Servlet 一致，步骤如下：</p> <ul><li>定义类，实现 javax.servlet.Filter 接口。</li> <li>覆写其中的 3 个方法。
<img src="https://cdn.jsdelivr.net/gh/langfeiyes/images-khub/image-20200523020941957.png" alt="image-20200523020941957"></li> <li>将写好的 Filter 交给 Tomcat 来管理（XML/注解）</li></ul> <h4 id="_7-2-4-hellofilter-代码演示"><a href="#_7-2-4-hellofilter-代码演示" class="header-anchor">#</a> 7.2.4 HelloFilter 代码演示</h4> <h5 id="_7-2-4-1-编写-hellofilter-java"><a href="#_7-2-4-1-编写-hellofilter-java" class="header-anchor">#</a> 7.2.4.1 编写 HelloFilter.java</h5> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">cn<span class="token punctuation">.</span>wolfcode<span class="token punctuation">.</span>web<span class="token punctuation">.</span>filter</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">HelloFilter</span> <span class="token keyword">implements</span> <span class="token class-name">Filter</span> <span class="token punctuation">{</span>

    <span class="token comment">// 初始化方法</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token class-name">FilterConfig</span> filterConfig<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">ServletException</span> <span class="token punctuation">{</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 过滤方法</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">ServletRequest</span> servletRequest<span class="token punctuation">,</span> <span class="token class-name">ServletResponse</span> servletResponse<span class="token punctuation">,</span> <span class="token class-name">FilterChain</span> filterChain<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span><span class="token punctuation">,</span> <span class="token class-name">ServletException</span> <span class="token punctuation">{</span>
        <span class="token comment">// 可以在这里做过滤操作</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;进来过滤了...&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 目前直接放行</span>
        filterChain<span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span>servletRequest<span class="token punctuation">,</span> servletResponse<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 销毁方法</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">destroy</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br></div></div><h5 id="_7-2-4-2-配置-hellofilter"><a href="#_7-2-4-2-配置-hellofilter" class="header-anchor">#</a> 7.2.4.2 配置 HelloFilter</h5> <p>使用 XML 配置，在 web.xml 配置如下：</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token comment">&lt;!-- 配置过滤器 --&gt;</span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-name</span><span class="token punctuation">&gt;</span></span>helloFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-name</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-class</span><span class="token punctuation">&gt;</span></span>cn.wolfcode.web.filter.HelloFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-class</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-mapping</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-name</span><span class="token punctuation">&gt;</span></span>helloFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-name</span><span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- 需过滤的资源地址，即访问 /hello 会执行到过滤器 HelloFilter 的 doFilter 方法 --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>url-pattern</span><span class="token punctuation">&gt;</span></span>/hello<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>url-pattern</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-mapping</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><h5 id="_7-2-4-3-测试"><a href="#_7-2-4-3-测试" class="header-anchor">#</a> 7.2.4.3 测试</h5> <p>启动 Tomcat 访问 localhost/hello 测试一下。</p> <h3 id="_7-3-过滤路径"><a href="#_7-3-过滤路径" class="header-anchor">#</a> 7.3 过滤路径</h3> <p>过滤器的 url-pattern 是指 Filter 对哪一些资源做过滤操作。注意与 Servlet 区别：</p> <ul><li><strong>Servlet 中的 url-pattern 的作用</strong>：为当前 Servlet 起一个资源名称，外界通过该名字找到对应的 Servlet 对象。</li> <li><strong>Filter 中的 url-pattern 的作用</strong>：指定对哪些资源做过滤。</li></ul> <p>配置过滤器路径举例说明：</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token operator">/</span>hello   	  <span class="token comment">// 说明当前 Filter 只会对 /hello 做拦截/过滤。</span>
<span class="token operator">/</span>employee     <span class="token comment">// 说明当前 Filter 只会对 /employee 资源做过滤</span>
<span class="token operator">/</span>system<span class="token comment">/*     // 说明当前 Filter 只会对以 /system/ 作为前缀的资源路径做拦截。
/*            // 说明当前 Filter 会对所有的资源访问都会被拦截。
</span></code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><h3 id="_7-4-filter-的生命周期"><a href="#_7-4-filter-的生命周期" class="header-anchor">#</a> 7.4 Filter 的生命周期</h3> <h4 id="_7-4-1-生命周期"><a href="#_7-4-1-生命周期" class="header-anchor">#</a> 7.4.1 生命周期</h4> <p><strong>Filter 的生命周期</strong>：指 Filter 从创建到销毁的整个过程。过程如下：</p> <ul><li><strong>对象的创建</strong>：在启动服务器的时候创建所有的 Filter 对象。</li> <li><strong>init 方法的执行</strong>：在启动服务器的时候调用 Filter 对象中的 init 方法。</li> <li><strong>doFilter 方法的执行</strong>：每次请求对应的资源的时候都会执行，只要路径符合。</li> <li><strong>destroy 方法的执行</strong>：正常关闭服务器的时候，执行销毁操作，非正常关闭不会执行。</li></ul> <h4 id="_7-4-2-代码验证"><a href="#_7-4-2-代码验证" class="header-anchor">#</a> 7.4.2 代码验证</h4> <p>修改 HelloFilter.java，提供构造器，并在其他初始化方法和销毁方法里面打印，修改完启动 Tomcat，访问 localhost/hello 测试一下，看打印结果。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">cn<span class="token punctuation">.</span>wolfcode<span class="token punctuation">.</span>web<span class="token punctuation">.</span>filter</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">HelloFilter</span> <span class="token keyword">implements</span> <span class="token class-name">Filter</span> <span class="token punctuation">{</span>

    <span class="token keyword">public</span> <span class="token class-name">HelloFilter</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;HelloFilter 对象被创建&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 初始化方法</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token class-name">FilterConfig</span> filterConfig<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">ServletException</span> <span class="token punctuation">{</span>
        <span class="token comment">// filterConfig 可以获取到配置初始化参数</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;初始化方法&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 过滤方法</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">ServletRequest</span> servletRequest<span class="token punctuation">,</span> <span class="token class-name">ServletResponse</span> servletResponse<span class="token punctuation">,</span> <span class="token class-name">FilterChain</span> filterChain<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span><span class="token punctuation">,</span> <span class="token class-name">ServletException</span> <span class="token punctuation">{</span>
        <span class="token comment">// 可以在这里做过滤操作</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;进来 HelloFilter 过滤了..&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 目前直接放行</span>
        filterChain<span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span>servletRequest<span class="token punctuation">,</span> servletResponse<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// 销毁方法</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">destroy</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;销毁方法&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br></div></div><h4 id="_7-4-3-执行顺序"><a href="#_7-4-3-执行顺序" class="header-anchor">#</a> 7.4.3 执行顺序</h4> <p>创建对象（一次）---&gt; init 方法（一次）---&gt; doFilter 方法（N 次）---&gt; destroy 方法(一次/ 0 次)</p> <h3 id="_7-5-filterchain-过滤器链"><a href="#_7-5-filterchain-过滤器链" class="header-anchor">#</a> 7.5 FilterChain（过滤器链）</h3> <p>在开发中会存在并配置了多个过滤器时，多个过滤器按照一定的顺序，排列起来，多个 Filter 组合在一起都形成一个 Filter 链，使用 FilterChain 对象来做牵引关联。</p> <p><img src="https://cdn.jsdelivr.net/gh/langfeiyes/images-khub/image-20200523021847210.png" alt="image-20200523021847210"></p> <p><strong>程序中，存在多个过滤器的时候，过滤器的先后执行顺序由谁来决定？</strong></p> <ul><li>由在 web.xml 中配置的 <code>&lt;filter-mapping&gt;</code> 的先后顺序来决定。</li> <li>注解配置时则是由 Filter 的名称的字母先后顺序来决定。</li></ul> <h3 id="_7-6-过滤方式-了解"><a href="#_7-6-过滤方式-了解" class="header-anchor">#</a> 7.6 过滤方式（了解）</h3> <p>默认过滤器只对请求操作做过滤，针对转发是没有做过滤的，若要对转发方式等做过滤，需要设置过滤方式。过滤方式如下：</p> <ul><li>REQUEST   ：一次全新的请求，只有全新的请求才会经过过滤器（默认）。</li> <li>FORWARD ：请求转发。</li> <li>ERROR       :   错误页面跳转。</li></ul> <h4 id="_7-6-1-过滤转发"><a href="#_7-6-1-过滤转发" class="header-anchor">#</a> 7.6.1 过滤转发</h4> <p>在 web.xml 修改 HelloFilter 的过滤器方式，如下：</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-mapping</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-name</span><span class="token punctuation">&gt;</span></span>helloFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-name</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>url-pattern</span><span class="token punctuation">&gt;</span></span>/*<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>url-pattern</span><span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- 过滤请求 --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dispatcher</span><span class="token punctuation">&gt;</span></span>REQUEST<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dispatcher</span><span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- 过滤转发 --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dispatcher</span><span class="token punctuation">&gt;</span></span>FORWARD<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dispatcher</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-mapping</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><h4 id="_7-6-2-过滤器错误"><a href="#_7-6-2-过滤器错误" class="header-anchor">#</a> 7.6.2 过滤器错误</h4> <h5 id="_7-6-2-1-编写-404-jsp-和-500-jsp"><a href="#_7-6-2-1-编写-404-jsp-和-500-jsp" class="header-anchor">#</a> 7.6.2.1 编写 404.jsp 和 500.jsp</h5> <p>在 web 目录下新建 404.jsp 和 500.jsp，404.jsp 内容提示用户访问的资源不存在，500.jsp 内容提示用户程序员正在努力修复程序。</p> <h5 id="_7-6-2-2-配置通用的错误页面"><a href="#_7-6-2-2-配置通用的错误页面" class="header-anchor">#</a> 7.6.2.2 配置通用的错误页面</h5> <p>在 web.xml 中配置如下：</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>error-page</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>error-code</span><span class="token punctuation">&gt;</span></span>404<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>error-code</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>location</span><span class="token punctuation">&gt;</span></span>/404.jsp<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>location</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>error-page</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>error-page</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>error-code</span><span class="token punctuation">&gt;</span></span>500<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>error-code</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>location</span><span class="token punctuation">&gt;</span></span>/500.jsp<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>location</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>error-page</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><h5 id="_7-6-2-3-修改过滤器过滤方式"><a href="#_7-6-2-3-修改过滤器过滤方式" class="header-anchor">#</a> 7.6.2.3 修改过滤器过滤方式</h5> <p>在 web.xml 修改 HelloFilter 的过滤器方式，如下：</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-mapping</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-name</span><span class="token punctuation">&gt;</span></span>helloFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-name</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>url-pattern</span><span class="token punctuation">&gt;</span></span>/*<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>url-pattern</span><span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- 过滤请求 --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dispatcher</span><span class="token punctuation">&gt;</span></span>REQUEST<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dispatcher</span><span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- 过滤转发 --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dispatcher</span><span class="token punctuation">&gt;</span></span>FORWARD<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dispatcher</span><span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- 过滤错误 --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>dispatcher</span><span class="token punctuation">&gt;</span></span>ERROR<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>dispatcher</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-mapping</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><h3 id="_7-7-字符编码过滤器"><a href="#_7-7-字符编码过滤器" class="header-anchor">#</a> 7.7 字符编码过滤器</h3> <h4 id="_7-7-1-编码过滤器引入"><a href="#_7-7-1-编码过滤器引入" class="header-anchor">#</a> 7.7.1 编码过滤器引入</h4> <p>之前编码处理的代码是直接写 Servlet 中的，那么它存在以下问题：</p> <ul><li>代码重复，无法复用，从增加维护成本。</li></ul> <p><strong>目标</strong>：一处设置，到处有效（设置一次，所有 Servlet 共用）
<strong>方案</strong>：访问到 Servlet 之前对请求中的编码做处理（Filter）</p> <h4 id="_7-7-2-代码实现"><a href="#_7-7-2-代码实现" class="header-anchor">#</a> 7.7.2 代码实现</h4> <h5 id="_7-7-2-1-修改所有-servlet"><a href="#_7-7-2-1-修改所有-servlet" class="header-anchor">#</a> 7.7.2.1 修改所有 Servlet</h5> <p>删除其中对请求编码的的处理的代码。</p> <h5 id="_7-7-2-2-编写-characterencodingfilter-java"><a href="#_7-7-2-2-编写-characterencodingfilter-java" class="header-anchor">#</a> 7.7.2.2 编写 CharacterEncodingFilter.java</h5> <p>统一在过滤器的 doFilter 方法中设置好编码为 UTF-8</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">cn<span class="token punctuation">.</span>wolfcode<span class="token punctuation">.</span>web<span class="token punctuation">.</span>filter</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">CharacterEncodingFilter</span> <span class="token keyword">implements</span> <span class="token class-name">Filter</span> <span class="token punctuation">{</span>
    
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token class-name">FilterConfig</span> filterConfig<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">ServletException</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">ServletRequest</span> servletRequest<span class="token punctuation">,</span> <span class="token class-name">ServletResponse</span> servletResponse<span class="token punctuation">,</span> <span class="token class-name">FilterChain</span> filterChain<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span><span class="token punctuation">,</span> <span class="token class-name">ServletException</span> <span class="token punctuation">{</span>
        <span class="token comment">// 设置请求编码</span>
        servletRequest<span class="token punctuation">.</span><span class="token function">setCharacterEncoding</span><span class="token punctuation">(</span><span class="token string">&quot;UTF-8&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 发行</span>
        filterChain<span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span>servletRequest<span class="token punctuation">,</span> servletResponse<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">destroy</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br></div></div><h5 id="_7-7-2-3-配置-characterencodingfilter"><a href="#_7-7-2-3-配置-characterencodingfilter" class="header-anchor">#</a> 7.7.2.3 配置 CharacterEncodingFilter</h5> <p>在 web.xml 配置此过滤器，如下：</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-name</span><span class="token punctuation">&gt;</span></span>characterEncodingFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-name</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-class</span><span class="token punctuation">&gt;</span></span>cn.wolfcode.web.filter.CharacterEncodingFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-class</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-mapping</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-name</span><span class="token punctuation">&gt;</span></span>characterEncodingFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-name</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>url-pattern</span><span class="token punctuation">&gt;</span></span>/*<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>url-pattern</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-mapping</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><h4 id="_7-7-3-字符编码可以配置"><a href="#_7-7-3-字符编码可以配置" class="header-anchor">#</a> 7.7.3 字符编码可以配置</h4> <p>在过滤器中，我们将请求参数的编码设值为 UTF-8，此时编码是写死在 Java 代码中的，若后期需要修改，那么这个 UTF-8 就是硬编码，不可以灵活配置。</p> <h5 id="_7-7-3-1-配置字符编码"><a href="#_7-7-3-1-配置字符编码" class="header-anchor">#</a> 7.7.3.1 配置字符编码</h5> <p>Filter 类似 Servlet 一样，也可以配置初始化参数。在 web.xml 配置如下：</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-name</span><span class="token punctuation">&gt;</span></span>characterEncodingFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-name</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-class</span><span class="token punctuation">&gt;</span></span>cn.wolfcode.web.filter.CharacterEncodingFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-class</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>init-param</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>param-name</span><span class="token punctuation">&gt;</span></span>encoding<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>param-name</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>param-value</span><span class="token punctuation">&gt;</span></span>UTF-8<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>param-value</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>init-param</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-mapping</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-name</span><span class="token punctuation">&gt;</span></span>characterEncodingFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-name</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>url-pattern</span><span class="token punctuation">&gt;</span></span>/*<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>url-pattern</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-mapping</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><h5 id="_7-7-3-2-修改-characterencodingfilter-java"><a href="#_7-7-3-2-修改-characterencodingfilter-java" class="header-anchor">#</a> 7.7.3.2 修改 CharacterEncodingFilter.java</h5> <p>在初始化方法里从 FilterConfig 对象中获取配置的 encoding 的初始化参数值。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">cn<span class="token punctuation">.</span>wolfcode<span class="token punctuation">.</span>web<span class="token punctuation">.</span>filter</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">CharacterEncodingFilter</span> <span class="token keyword">implements</span> <span class="token class-name">Filter</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token class-name">String</span> encoding<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token class-name">FilterConfig</span> filterConfig<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">ServletException</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>encoding <span class="token operator">=</span> filterConfig<span class="token punctuation">.</span><span class="token function">getInitParameter</span><span class="token punctuation">(</span><span class="token string">&quot;encoding&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">ServletRequest</span> servletRequest<span class="token punctuation">,</span> <span class="token class-name">ServletResponse</span> servletResponse<span class="token punctuation">,</span> <span class="token class-name">FilterChain</span> filterChain<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span><span class="token punctuation">,</span> <span class="token class-name">ServletException</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token class-name">StringUtil</span><span class="token punctuation">.</span><span class="token function">hasLength</span><span class="token punctuation">(</span>encoding<span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">// 设置请求编码</span>
            servletRequest<span class="token punctuation">.</span><span class="token function">setCharacterEncoding</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>encoding<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token comment">// 放行</span>
        filterChain<span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span>servletRequest<span class="token punctuation">,</span> servletResponse<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">destroy</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>

    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br></div></div><h4 id="_7-7-4-字符编码覆盖设置"><a href="#_7-7-4-字符编码覆盖设置" class="header-anchor">#</a> 7.7.4 字符编码覆盖设置</h4> <p>因为可能存在多个过滤器且都设置字符编码，可以让开发者能够选择是否覆盖之前的字符编码，这种设计才是最灵活的。</p> <h5 id="_7-7-4-1-配置字符编码是否覆盖"><a href="#_7-7-4-1-配置字符编码是否覆盖" class="header-anchor">#</a> 7.7.4.1 配置字符编码是否覆盖</h5> <p>在 web.xml 配置如下：</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-name</span><span class="token punctuation">&gt;</span></span>characterEncodingFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-name</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-class</span><span class="token punctuation">&gt;</span></span>cn.wolfcode.web.filter.CharacterEncodingFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-class</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>init-param</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>param-name</span><span class="token punctuation">&gt;</span></span>encoding<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>param-name</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>param-value</span><span class="token punctuation">&gt;</span></span>UTF-8<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>param-value</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>init-param</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>init-param</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>param-name</span><span class="token punctuation">&gt;</span></span>force<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>param-name</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>param-value</span><span class="token punctuation">&gt;</span></span>true<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>param-value</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>init-param</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-mapping</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-name</span><span class="token punctuation">&gt;</span></span>characterEncodingFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-name</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>url-pattern</span><span class="token punctuation">&gt;</span></span>/*<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>url-pattern</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-mapping</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br></div></div><h5 id="_7-7-4-2-修改-characterencodingfilter-java"><a href="#_7-7-4-2-修改-characterencodingfilter-java" class="header-anchor">#</a> 7.7.4.2 修改 characterEncodingFilter.java</h5> <p>在初始化方法里从 FilterConfig 对象中获取配置的 encoding 的初始化参数值。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">cn<span class="token punctuation">.</span>wolfcode<span class="token punctuation">.</span>web<span class="token punctuation">.</span>filter</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">CharacterEncodingFilter</span> <span class="token keyword">implements</span> <span class="token class-name">Filter</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token class-name">String</span> encoding<span class="token punctuation">;</span>
    <span class="token keyword">private</span> <span class="token keyword">boolean</span> force<span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token class-name">FilterConfig</span> filterConfig<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">ServletException</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>encoding <span class="token operator">=</span> filterConfig<span class="token punctuation">.</span><span class="token function">getInitParameter</span><span class="token punctuation">(</span><span class="token string">&quot;encoding&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>force <span class="token operator">=</span> <span class="token class-name">Boolean</span><span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span>filterConfig<span class="token punctuation">.</span><span class="token function">getInitParameter</span><span class="token punctuation">(</span><span class="token string">&quot;force&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">ServletRequest</span> servletRequest<span class="token punctuation">,</span> <span class="token class-name">ServletResponse</span> servletResponse<span class="token punctuation">,</span> <span class="token class-name">FilterChain</span> filterChain<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span><span class="token punctuation">,</span> <span class="token class-name">ServletException</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span><span class="token class-name">StringUtil</span><span class="token punctuation">.</span><span class="token function">hasLength</span><span class="token punctuation">(</span>encoding<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">// 若配置强制或者之前设置过请求字符编码的话</span>
            <span class="token keyword">if</span><span class="token punctuation">(</span>force <span class="token operator">||</span> servletRequest<span class="token punctuation">.</span><span class="token function">getCharacterEncoding</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
                servletRequest<span class="token punctuation">.</span><span class="token function">setCharacterEncoding</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">.</span>encoding<span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
        filterChain<span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span>servletRequest<span class="token punctuation">,</span> servletResponse<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">destroy</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br></div></div><h3 id="_7-8-登录校验过滤器"><a href="#_7-8-登录校验过滤器" class="header-anchor">#</a> 7.8 登录校验过滤器</h3> <h4 id="_7-8-1-登录校验过滤器引入"><a href="#_7-8-1-登录校验过滤器引入" class="header-anchor">#</a> 7.8.1 登录校验过滤器引入</h4> <p>在实际开发中，我们项目中会存在很多的资源都需要在登录之后才能访问，所以我们需要在请求到达这些资源之前先判断当前用户是否登录，如果没有应该跳转到登录页面。之前我们是在需要登录访问的的资源加上登录判断代码，代码如下：</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token class-name">Object</span> obj <span class="token operator">=</span> req<span class="token punctuation">.</span><span class="token function">getSession</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">&quot;USER_IN_SESSION&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>obj <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    resp<span class="token punctuation">.</span><span class="token function">sendRedirect</span><span class="token punctuation">(</span><span class="token string">&quot;/login.jsp&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>以上操作能够解决登录检查的需求，但存在大量重复代码，在每个资源的代码中都会编写检查登录的代码，从增加维护成本。</p> <p><strong>目标</strong>：一处设置，到处有效（设置一次，所有 Servlet 共用）。
<strong>方案</strong>：访问到 Servlet 之前对请求进行登录校验处理（Filter）。</p> <h4 id="_7-8-2-代码实现"><a href="#_7-8-2-代码实现" class="header-anchor">#</a> 7.8.2 代码实现</h4> <h5 id="_7-8-2-1-修改所有-servlet"><a href="#_7-8-2-1-修改所有-servlet" class="header-anchor">#</a> 7.8.2.1 修改所有 Servlet</h5> <p>删除其中对请求登录校验处理的代码。</p> <h5 id="_7-8-2-2-编写-checkloginfilter-java"><a href="#_7-8-2-2-编写-checkloginfilter-java" class="header-anchor">#</a> 7.8.2.2 编写 CheckLoginFilter.java</h5> <p>过滤器请求，做登录校验。</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">cn<span class="token punctuation">.</span>wolfcode<span class="token punctuation">.</span>web<span class="token punctuation">.</span>filter</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">CheckLoginFilter</span> <span class="token keyword">implements</span> <span class="token class-name">Filter</span> <span class="token punctuation">{</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token class-name">FilterConfig</span> filterConfig<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">ServletException</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">ServletRequest</span> servletRequest<span class="token punctuation">,</span> <span class="token class-name">ServletResponse</span> servletResponse<span class="token punctuation">,</span> <span class="token class-name">FilterChain</span> filterChain<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span><span class="token punctuation">,</span> <span class="token class-name">ServletException</span> <span class="token punctuation">{</span>
        <span class="token comment">// 把请求和响应转化为符合 HTTP 协议的对象</span>
        <span class="token class-name">HttpServletRequest</span> req <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span><span class="token punctuation">)</span> servletRequest<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">HttpServletResponse</span> resp <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">HttpServletResponse</span><span class="token punctuation">)</span> servletResponse<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token class-name">Object</span> obj <span class="token operator">=</span> req<span class="token punctuation">.</span><span class="token function">getSession</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">&quot;USER_IN_SESSION&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 没有登录，重定向到登录页面</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span>obj <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            resp<span class="token punctuation">.</span><span class="token function">sendRedirect</span><span class="token punctuation">(</span><span class="token string">&quot;/login.jsp&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">return</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token comment">// 登录过，放行访问</span>
        filterChain<span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span> resp<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">destroy</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br></div></div><h5 id="_7-8-2-3-配置-checkloginfilter"><a href="#_7-8-2-3-配置-checkloginfilter" class="header-anchor">#</a> 7.8.2.3 配置 CheckLoginFilter</h5> <p>在 web.xml 配置此过滤器，如下：</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-name</span><span class="token punctuation">&gt;</span></span>checkLoginFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-name</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-class</span><span class="token punctuation">&gt;</span></span>cn.wolfcode.web.filter.CheckLoginFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-class</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-mapping</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-name</span><span class="token punctuation">&gt;</span></span>checkLoginFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-name</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>url-pattern</span><span class="token punctuation">&gt;</span></span>/*<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>url-pattern</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-mapping</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><h5 id="_7-8-2-4-匿名访问资源"><a href="#_7-8-2-4-匿名访问资源" class="header-anchor">#</a> 7.8.2.4 匿名访问资源</h5> <p>匿名访问资源指的是不需要登录也可以访问的资源，比如 /login.jsp，/login，/randomCode 和静态资源等等。若不排除，那么当浏览器中请求这些资源，也需要登录，这就会造成这些资源访问不到了。</p> <p>针对上面的情况，只需要指定 CheckLoginFilter 对哪些资源做登录校验处理或者不对哪些资源做登录校验处理。</p> <p><strong>方式一</strong></p> <p>指定 CheckLoginFilter 不对哪些资源做登录校验处理。</p> <p>修改 CheckLoginFilter，配置初始化参数，指定哪些资源不做登录校验，如下：</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-name</span><span class="token punctuation">&gt;</span></span>checkLoginFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-name</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-class</span><span class="token punctuation">&gt;</span></span>cn.wolfcode.web.filter.CheckLoginFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-class</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>init-param</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>param-name</span><span class="token punctuation">&gt;</span></span>unCheckUri<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>param-name</span><span class="token punctuation">&gt;</span></span>
        <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>param-value</span><span class="token punctuation">&gt;</span></span>/login.jsp;/login;/randomCode<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>param-value</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>init-param</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-mapping</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-name</span><span class="token punctuation">&gt;</span></span>checkLoginFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-name</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>url-pattern</span><span class="token punctuation">&gt;</span></span>/*<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>url-pattern</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-mapping</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">cn<span class="token punctuation">.</span>wolfcode<span class="token punctuation">.</span>web<span class="token punctuation">.</span>filter</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">CheckLoginFilter</span> <span class="token keyword">implements</span> <span class="token class-name">Filter</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> unCheckUriList<span class="token punctuation">;</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token class-name">FilterConfig</span> filterConfig<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">ServletException</span> <span class="token punctuation">{</span>
        <span class="token keyword">this</span><span class="token punctuation">.</span>unCheckUriList <span class="token operator">=</span> <span class="token class-name">Arrays</span><span class="token punctuation">.</span><span class="token function">asList</span><span class="token punctuation">(</span>filterConfig<span class="token punctuation">.</span><span class="token function">getInitParameter</span><span class="token punctuation">(</span><span class="token string">&quot;unCheckUri&quot;</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">split</span><span class="token punctuation">(</span><span class="token string">&quot;;&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">ServletRequest</span> servletRequest<span class="token punctuation">,</span> <span class="token class-name">ServletResponse</span> servletResponse<span class="token punctuation">,</span> <span class="token class-name">FilterChain</span> filterChain<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span><span class="token punctuation">,</span> <span class="token class-name">ServletException</span> <span class="token punctuation">{</span>
        <span class="token class-name">HttpServletRequest</span> req <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span><span class="token punctuation">)</span> servletRequest<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">HttpServletResponse</span> resp <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">HttpServletResponse</span><span class="token punctuation">)</span> servletResponse<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token class-name">Object</span> obj <span class="token operator">=</span> req<span class="token punctuation">.</span><span class="token function">getSession</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">&quot;USER_IN_SESSION&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 获取请求的资源路径</span>
        <span class="token class-name">String</span> uri <span class="token operator">=</span> req<span class="token punctuation">.</span><span class="token function">getRequestURI</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 没有登录且访问的不是匿名资源，重定向到登录页面</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span>obj <span class="token operator">==</span> <span class="token keyword">null</span> <span class="token operator">&amp;&amp;</span> <span class="token operator">!</span>unCheckUriList<span class="token punctuation">.</span><span class="token function">contains</span><span class="token punctuation">(</span>uri<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            resp<span class="token punctuation">.</span><span class="token function">sendRedirect</span><span class="token punctuation">(</span><span class="token string">&quot;/login.jsp&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">return</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token comment">// 登录过，放行访问</span>
        filterChain<span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span> resp<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">destroy</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>

    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br></div></div><p><strong>方式二</strong></p> <p>因为会发现，上面那样处理还是会导致静态资源不可以访问到，而实际开发中，我们需要排除的资源较多的话，尤其是像静态资源，会很麻烦。所以这次指定 CheckLoginFilter 对哪些资源做登录校验处理。将需要受检查的资源通通存放到 check 路径下。</p> <p>修改 CheckLoginFilter 的过滤路径，如下：</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-name</span><span class="token punctuation">&gt;</span></span>checkLoginFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-name</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-class</span><span class="token punctuation">&gt;</span></span>cn.wolfcode.web.filter.CheckLoginFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-class</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-mapping</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>filter-name</span><span class="token punctuation">&gt;</span></span>checkLoginFilter<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-name</span><span class="token punctuation">&gt;</span></span>
    <span class="token comment">&lt;!-- 只有在 check 路径下的资源访问会做登录的校验 --&gt;</span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>url-pattern</span><span class="token punctuation">&gt;</span></span>/check/*<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>url-pattern</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>filter-mapping</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><p>修改 CheckLoginFilter，如下：</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">cn<span class="token punctuation">.</span>wolfcode<span class="token punctuation">.</span>web<span class="token punctuation">.</span>filter</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">CheckLoginFilter</span> <span class="token keyword">implements</span> <span class="token class-name">Filter</span> <span class="token punctuation">{</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">init</span><span class="token punctuation">(</span><span class="token class-name">FilterConfig</span> filterConfig<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">ServletException</span> <span class="token punctuation">{</span>

    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">doFilter</span><span class="token punctuation">(</span><span class="token class-name">ServletRequest</span> servletRequest<span class="token punctuation">,</span> <span class="token class-name">ServletResponse</span> servletResponse<span class="token punctuation">,</span> <span class="token class-name">FilterChain</span> filterChain<span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">IOException</span><span class="token punctuation">,</span> <span class="token class-name">ServletException</span> <span class="token punctuation">{</span>
        <span class="token class-name">HttpServletRequest</span> req <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">HttpServletRequest</span><span class="token punctuation">)</span> servletRequest<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">HttpServletResponse</span> resp <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">HttpServletResponse</span><span class="token punctuation">)</span> servletResponse<span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token class-name">Object</span> obj <span class="token operator">=</span> req<span class="token punctuation">.</span><span class="token function">getSession</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getAttribute</span><span class="token punctuation">(</span><span class="token string">&quot;USER_IN_SESSION&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token comment">// 没有登录，重定向到登录页面</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span>obj <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            resp<span class="token punctuation">.</span><span class="token function">sendRedirect</span><span class="token punctuation">(</span><span class="token string">&quot;/login.jsp&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            <span class="token keyword">return</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
        <span class="token comment">// 登录过，放行访问</span>
        filterChain<span class="token punctuation">.</span><span class="token function">doFilter</span><span class="token punctuation">(</span>req<span class="token punctuation">,</span> resp<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">destroy</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>

    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br></div></div><p>最后只要修改需要做登录校验的资源，加上 /check 路径即可（记得把 list.jsp 查询产品的路径和登录成功重定向的的路径改了），如下：</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@WebServlet</span><span class="token punctuation">(</span><span class="token string">&quot;/check/product&quot;</span><span class="token punctuation">)</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ProductServlet</span> <span class="token keyword">extends</span> <span class="token class-name">HttpServlet</span> <span class="token punctuation">{</span>
    <span class="token comment">// 省略......</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><h2 id="八-监听器-listener"><a href="#八-监听器-listener" class="header-anchor">#</a> 八 监听器 Listener</h2> <p>Listener 是 Java Web 组件之一，主要的作用是用于<strong>监听作用域对象</strong>的创建和销毁动作以及<strong>作用域属性值</strong>的改变动作。若用户触发了这些动作，那么会立即执行相应的的监听器的操作。</p> <h3 id="_8-1-监听什么及分类"><a href="#_8-1-监听什么及分类" class="header-anchor">#</a> 8.1 监听什么及分类</h3> <p><strong>监听的对象</strong>：作用域对象，作用域属性。
<strong>监听的动作</strong>：作用域对象的创建和销毁，作用域属值的增删改。</p> <p>监听器分类</p> <ul><li>按作用域对象：
<ul><li>ServletRequestListener</li> <li>HttpSessionListener</li> <li>ServletContextListener</li></ul></li> <li>按作用域属性分：
<ul><li>ServletRequestAttributeListener</li> <li>HttpSessionAttributeListener</li> <li>ServletContextAttributeListener</li></ul></li></ul> <h3 id="_8-2-开发监听器的步骤"><a href="#_8-2-开发监听器的步骤" class="header-anchor">#</a> 8.2 开发监听器的步骤</h3> <ul><li>创建一个类，根据需求实现对应的接口。</li> <li>实现其中的方法。</li> <li>将监听器交给 Tomcat 管理。</li></ul> <h3 id="_8-3-统计游客数量"><a href="#_8-3-统计游客数量" class="header-anchor">#</a> 8.3 统计游客数量</h3> <p>案例：统计游客数量。</p> <h4 id="_8-3-1-编写-visitorlistener-java"><a href="#_8-3-1-编写-visitorlistener-java" class="header-anchor">#</a> 8.3.1 编写 VisitorListener.java</h4> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">cn<span class="token punctuation">.</span>wolfcode<span class="token punctuation">.</span>web<span class="token punctuation">.</span>listener</span><span class="token punctuation">;</span>

<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">VisitorListener</span> <span class="token keyword">implements</span> <span class="token class-name">HttpSessionListener</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">long</span> totalCount <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>

    <span class="token comment">// Session 对象创建会执行下面的方法</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">sessionCreated</span><span class="token punctuation">(</span><span class="token class-name">HttpSessionEvent</span> httpSessionEvent<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        totalCount<span class="token operator">++</span><span class="token punctuation">;</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;在线人数：&quot;</span> <span class="token operator">+</span> totalCount<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token comment">// Session 对象销毁会执行下面的方法</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">sessionDestroyed</span><span class="token punctuation">(</span><span class="token class-name">HttpSessionEvent</span> httpSessionEvent<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        totalCount<span class="token operator">--</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br></div></div><h4 id="_8-3-2-配置-visitorlistener"><a href="#_8-3-2-配置-visitorlistener" class="header-anchor">#</a> 8.3.2 配置 VisitorListener</h4> <p>可以使用注解配置（直接在自己写监听器类上贴 @WebListener 即可），也可以是 XML 配置，XML 配置如下：</p> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>listener</span><span class="token punctuation">&gt;</span></span>
    <span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>listener-class</span><span class="token punctuation">&gt;</span></span>cn.wolfcode.web.listener.VisitorListener<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>listener-class</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>listener</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><h3 id="_8-4-创建系统默认管理员"><a href="#_8-4-创建系统默认管理员" class="header-anchor">#</a> 8.4 创建系统默认管理员</h3> <p>一般系统最开始部署到用户的服务器时，需要在用户的表中添加一个默认的超级管理员账户，再由该管理员来管理其他的账户的添删改查操作。</p> <h4 id="_8-4-1-思考的问题"><a href="#_8-4-1-思考的问题" class="header-anchor">#</a> 8.4.1 思考的问题</h4> <ul><li>超级管理员什么时候创建？服务器启动的时候创建。</li> <li>哪些技术可以在服务器启动做操作？
答案：可以使用 Servlet 和 Filter 来实现，也可以使用 ServletContextListener 这个监听器来完成，这个监听器可以用来监听 ServletContext 对象的创建，而这个对象的创建就是在 Tomcat 启动的时候。</li></ul> <h4 id="_8-4-2-编写并配置-createsuperuserlistener"><a href="#_8-4-2-编写并配置-createsuperuserlistener" class="header-anchor">#</a> 8.4.2 编写并配置 CreateSuperUserListener</h4> <p>在其 contextInitialized 方法中创建管理员账户：</p> <ul><li>查询用户表中是否存在管理员的账户。</li> <li><strong>存在则不做操作，不存在则创建账号</strong>。</li></ul> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">cn<span class="token punctuation">.</span>wolfcode<span class="token punctuation">.</span>web<span class="token punctuation">.</span>listener</span><span class="token punctuation">;</span>

<span class="token annotation punctuation">@WebListener</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">CreateSuperUserListener</span> <span class="token keyword">implements</span> <span class="token class-name">ServletContextListener</span> <span class="token punctuation">{</span>

    <span class="token keyword">private</span> <span class="token class-name">IUserDAO</span> userDAO <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">UserDAOImpl</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

    <span class="token comment">// 容器启动的时候会执行下面的方法</span>
    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">contextInitialized</span><span class="token punctuation">(</span><span class="token class-name">ServletContextEvent</span> servletContextEvent<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment">// 判断是否存在超级管理员，存在说明不是第一次部署，不能再创建账号</span>
        <span class="token class-name">User</span> user <span class="token operator">=</span> userDAO<span class="token punctuation">.</span><span class="token function">checkUser</span><span class="token punctuation">(</span><span class="token string">&quot;admin&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token keyword">if</span><span class="token punctuation">(</span>user <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
            <span class="token comment">// 保存管理员账号</span>
            <span class="token class-name">User</span> adminUser <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">User</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            adminUser<span class="token punctuation">.</span><span class="token function">setUsername</span><span class="token punctuation">(</span><span class="token string">&quot;admin&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            adminUser<span class="token punctuation">.</span><span class="token function">setPassword</span><span class="token punctuation">(</span><span class="token string">&quot;admin&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
            userDAO<span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span>adminUser<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token annotation punctuation">@Override</span>
    <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">contextDestroyed</span><span class="token punctuation">(</span><span class="token class-name">ServletContextEvent</span> servletContextEvent<span class="token punctuation">)</span> <span class="token punctuation">{</span>

    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br></div></div><h4 id="_8-4-3-修改-iuserdao-和-userdaoimpl"><a href="#_8-4-3-修改-iuserdao-和-userdaoimpl" class="header-anchor">#</a> 8.4.3 修改 IUserDAO 和 UserDAOImpl</h4> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">void</span> <span class="token function">insert</span><span class="token punctuation">(</span><span class="token class-name">User</span> user<span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">insert</span><span class="token punctuation">(</span><span class="token class-name">User</span> user<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">SqlSession</span> session <span class="token operator">=</span> <span class="token class-name">MyBatisUtil</span><span class="token punctuation">.</span><span class="token function">getSession</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    session<span class="token punctuation">.</span><span class="token function">insert</span><span class="token punctuation">(</span><span class="token string">&quot;cn.wolfcode.mapper.UserMapper.insert&quot;</span><span class="token punctuation">,</span> user<span class="token punctuation">)</span><span class="token punctuation">;</span>
    session<span class="token punctuation">.</span><span class="token function">commit</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    session<span class="token punctuation">.</span><span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><h4 id="_8-4-4-修改-usermapper-xml"><a href="#_8-4-4-修改-usermapper-xml" class="header-anchor">#</a> 8.4.4 修改 UserMapper.xml</h4> <div class="language-xml line-numbers-mode"><pre class="language-xml"><code><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>insert</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>insert<span class="token punctuation">&quot;</span></span> <span class="token attr-name">useGeneratedKeys</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>true<span class="token punctuation">&quot;</span></span> <span class="token attr-name">keyProperty</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>id<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
    INSERT INTO user(username, password, headImg) VALUES(#{username}, #{password}, #{headImg})
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>insert</span><span class="token punctuation">&gt;</span></span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><h2 id="九-页面美化-拓展"><a href="#九-页面美化-拓展" class="header-anchor">#</a> 九 页面美化（拓展）</h2> <p>操作步骤：</p> <ol><li><p>拷贝前端写的页面</p> <p>根据给的目录把对应的文件拷贝到项目下，css js login.jsp common/input.jsp common/list.jsp</p></li> <li><p>修改 list.jsp 来显示列表的数据</p> <p>保留行中的编辑和修改按钮（带有样式），加入遍历到的货品数据</p></li> <li><p>加入高级查询的表单数据</p></li> <li><p>修改分页条的 totalPage 和 currentPage （common/page.jsp）</p></li> <li><p>加入 input.jsp -&gt; 修改 ProductServlet 加入分发器，可以跳转到 input.jsp</p></li> <li><p>修改 input.jsp ，一块一块表单控件的 div 拷贝修改即可</p></li> <li><p>把编辑删除，提交完成后台功能即可</p></li> <li><p>把用户头像修改加入项目中</p></li></ol> <p><img src="https://cdn.jsdelivr.net/gh/langfeiyes/images-khub/image-20200523174005151.png" alt="image-20200523174005151"></p> <p><img src="https://cdn.jsdelivr.net/gh/langfeiyes/images-khub/image-20200523174018678.png" alt="image-20200523174018678"></p> <p><img src="https://cdn.jsdelivr.net/gh/langfeiyes/images-khub/image-20200523174033445.png" alt="image-20200523174033445"></p> <h2 id="十、小结与作业"><a href="#十、小结与作业" class="header-anchor">#</a> 十、小结与作业</h2> <h3 id="_10-1-小结"><a href="#_10-1-小结" class="header-anchor">#</a> 10.1 小结</h3> <ul><li>掌握分页基本逻辑</li> <li>掌握分页实现-前端-表现层-持久层-业务层</li> <li>掌握条件查询-QueryObject</li> <li>掌握Mybatis动态SQL</li> <li>掌握用户注销逻辑实现</li> <li>掌握记住用户逻辑实现</li> <li>掌握验证码实现</li> <li>掌握过滤器实现</li> <li>掌握监听器实现</li></ul> <h3 id="_10-2-作业"><a href="#_10-2-作业" class="header-anchor">#</a> 10.2 作业</h3> <ul><li><p>梳理分页查询的流程,独立画流程图</p></li> <li><p>实现分页功能(实现持久层分页,实现业务层的分页,实现前台的分页)（两个模型以上）</p></li> <li><p>理解过滤查询原理</p></li> <li><p>完成过滤查询流程分析和图文表示</p></li> <li><p>完成过滤查询代码实现</p></li> <li><p>解决翻页表单过滤查询条件数据丢失问题</p></li> <li><p>自行找一张表，从零开始完成过滤和分页查询</p></li> <li><p>拓展练习关键字查询(不做作业要求)</p></li> <li><p>实现用户注销,记住账号,验证码功能</p></li> <li><p>实现字符编码过滤器</p></li> <li><p>实现登录校验过滤器</p></li> <li><p>使用监听器实现系统管理员账号的创建</p></li> <li><p>根据教材完成页面美化操作(不做要求)</p></li></ul></div></div>  <div class="page-edit"><!----> <div class="tags"><a href="/tags/?tag=MIS" title="标签">#MIS</a></div> <!----></div> <div class="page-nav-wapper"><div class="page-nav-centre-wrap"><a href="/pages/73e2cb/" class="page-nav-centre page-nav-centre-prev"><div class="tooltip">文件上传与下载和登录</div></a> <a href="/pages/71d587/" class="page-nav-centre page-nav-centre-next"><div class="tooltip">Maven</div></a></div> <div class="page-nav"><p class="inner"><span class="prev">
        ←
        <a href="/pages/73e2cb/" class="prev">文件上传与下载和登录</a></span> <span class="next"><a href="/pages/71d587/">Maven</a>→
      </span></p></div></div></div> <div class="article-list"><div class="article-title"><a href="/archives/" class="iconfont icon-bi">最近更新</a></div> <div class="article-wrapper"><dl><dd>01</dd> <dt><a href="/pages/0c07b2/"><div>
            IT杂货铺
            <!----></div></a> <span class="date">03-23</span></dt></dl><dl><dd>02</dd> <dt><a href="/pages/705b35/"><div>
            人事百问
            <!----></div></a> <span class="date">03-22</span></dt></dl><dl><dd>03</dd> <dt><a href="/pages/78eb56/"><div>
            MyBatis-Plus
            <!----></div></a> <span class="date">03-12</span></dt></dl> <dl><dd></dd> <dt><a href="/archives/" class="more">更多文章&gt;</a></dt></dl></div></div></main></div> <div class="footer"><div class="icons"><a href="mailto:langfeiyes@163.com" title="发邮件" target="_blank" class="iconfont icon-youjian"></a><a href="https://github.com/langfeiyes" title="GitHub" target="_blank" class="iconfont icon-github"></a><a href="https://music.163.com/#/playlist?id=755597173" title="听音乐" target="_blank" class="iconfont icon-erji"></a></div> 
  Theme by
  <a href="https://github.com/xugaoyi/vuepress-theme-vdoing" target="_blank" title="本站主题">Vdoing</a> 
    | Copyright © 2024-2024
    <span><a href="https://beian.miit.gov.cn/" target="_blank">粤ICP备18007927号-1</a></span></div> <div class="buttons"><div title="返回顶部" class="button blur go-to-top iconfont icon-fanhuidingbu" style="display:none;"></div> <div title="去评论" class="button blur go-to-comment iconfont icon-pinglun" style="display:none;"></div> <div title="主题模式" class="button blur theme-mode-but iconfont icon-zhuti"><ul class="select-box" style="display:none;"><li class="iconfont icon-zidong">
          跟随系统
        </li><li class="iconfont icon-rijianmoshi">
          浅色模式
        </li><li class="iconfont icon-yejianmoshi">
          深色模式
        </li><li class="iconfont icon-yuedu">
          阅读模式
        </li></ul></div></div> <!----> <!----> <!----></div><div class="global-ui"><div></div></div></div>
    <script src="/assets/js/app.a2a00aa5.js" defer></script><script src="/assets/js/2.256f807a.js" defer></script><script src="/assets/js/45.0ddf7e7f.js" defer></script>
  </body>
</html>
